ntdll: Do not fill the IOSB or signal completion on failure in tape_DeviceIoControl().
[wine.git] / dlls / ntdll / unix / tape.c
blobf513e5588985021e10501860d8357821a9a9daf7
1 /*
2 * TAPE support
4 * Copyright 2006 Hans Leidekker
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 #ifdef HAVE_SYS_MTIO_H
36 #include <sys/mtio.h>
37 #endif
39 #if !defined(MTCOMPRESSION) && defined(MTCOMP)
40 #define MTCOMPRESSION MTCOMP
41 #endif
42 #if !defined(MTSETBLK) && defined(MTSETBSIZ)
43 #define MTSETBLK MTSETBSIZ
44 #endif
45 #if !defined(MTSETBLK) && defined(MTSRSZ)
46 #define MTSETBLK MTSRSZ
47 #endif
48 #ifndef MT_ST_BLKSIZE_MASK
49 #define MT_ST_BLKSIZE_MASK 0xffffff
50 #endif
51 /* Darwin 7.9.0 has MTSETBSIZ instead of MTSETBLK */
52 #if !defined(MTSETBLK) && defined(MTSETBSIZ)
53 #define MTSETBLK MTSETBSIZ
54 #endif
56 #include "ntstatus.h"
57 #define WIN32_NO_STATUS
58 #include "windef.h"
59 #include "winternl.h"
60 #include "winioctl.h"
61 #include "ddk/ntddtape.h"
62 #include "wine/server.h"
63 #include "unix_private.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(tape);
68 static const char *io2str( unsigned int io )
70 switch (io)
72 #define X(x) case (x): return #x
73 X(IOCTL_TAPE_CHECK_VERIFY);
74 X(IOCTL_TAPE_CREATE_PARTITION);
75 X(IOCTL_TAPE_ERASE);
76 X(IOCTL_TAPE_FIND_NEW_DEVICES);
77 X(IOCTL_TAPE_GET_DRIVE_PARAMS);
78 X(IOCTL_TAPE_GET_MEDIA_PARAMS);
79 X(IOCTL_TAPE_GET_POSITION);
80 X(IOCTL_TAPE_GET_STATUS);
81 X(IOCTL_TAPE_PREPARE);
82 X(IOCTL_TAPE_SET_DRIVE_PARAMS);
83 X(IOCTL_TAPE_SET_MEDIA_PARAMS);
84 X(IOCTL_TAPE_SET_POSITION);
85 X(IOCTL_TAPE_WRITE_MARKS);
86 #undef X
87 default: return wine_dbg_sprintf("IOCTL_TAPE_%d\n", io);
91 /******************************************************************
92 * TAPE_GetStatus
94 #ifdef HAVE_SYS_MTIO_H
95 static inline NTSTATUS TAPE_GetStatus( int error )
97 if (!error) return STATUS_SUCCESS;
98 return errno_to_status( errno );
100 #endif
102 /******************************************************************
103 * TAPE_CreatePartition
105 static NTSTATUS TAPE_CreatePartition( int fd, const TAPE_CREATE_PARTITION *data )
107 #ifdef HAVE_SYS_MTIO_H
108 struct mtop cmd;
110 TRACE( "fd: %d method: 0x%08x count: 0x%08x size: 0x%08x\n",
111 fd, (int)data->Method, (int)data->Count, (int)data->Size );
113 if (data->Count > 1)
115 WARN( "Creating more than 1 partition is not supported\n" );
116 return STATUS_INVALID_PARAMETER;
119 switch (data->Method)
121 #ifdef MTMKPART
122 case TAPE_FIXED_PARTITIONS:
123 case TAPE_SELECT_PARTITIONS:
124 cmd.mt_op = MTMKPART;
125 cmd.mt_count = 0;
126 break;
127 case TAPE_INITIATOR_PARTITIONS:
128 cmd.mt_op = MTMKPART;
129 cmd.mt_count = data->Size;
130 break;
131 #endif
132 default:
133 ERR( "Unhandled method: 0x%08x\n", (int)data->Method );
134 return STATUS_INVALID_PARAMETER;
137 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
138 #else
139 FIXME( "Not implemented.\n" );
140 return STATUS_NOT_SUPPORTED;
141 #endif
144 /******************************************************************
145 * TAPE_Erase
147 static NTSTATUS TAPE_Erase( int fd, const TAPE_ERASE *data )
149 #ifdef HAVE_SYS_MTIO_H
150 struct mtop cmd;
152 TRACE( "fd: %d type: 0x%08x immediate: 0x%02x\n",
153 fd, (int)data->Type, (int)data->Immediate );
155 switch (data->Type)
157 case TAPE_ERASE_LONG:
158 cmd.mt_op = MTERASE;
159 cmd.mt_count = 1;
160 break;
161 case TAPE_ERASE_SHORT:
162 cmd.mt_op = MTERASE;
163 cmd.mt_count = 0;
164 break;
165 default:
166 ERR( "Unhandled type: 0x%08x\n", (int)data->Type );
167 return STATUS_INVALID_PARAMETER;
170 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
171 #else
172 FIXME( "Not implemented.\n" );
173 return STATUS_NOT_SUPPORTED;
174 #endif
177 /******************************************************************
178 * TAPE_GetDriveParams
180 static NTSTATUS TAPE_GetDriveParams( int fd, TAPE_GET_DRIVE_PARAMETERS *data )
182 #ifdef HAVE_SYS_MTIO_H
183 struct mtget get;
184 NTSTATUS status;
186 TRACE( "fd: %d\n", fd );
188 memset( data, 0, sizeof(TAPE_GET_DRIVE_PARAMETERS) );
190 status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
191 if (status != STATUS_SUCCESS)
192 return status;
194 data->ECC = FALSE;
195 data->Compression = FALSE;
196 data->DataPadding = FALSE;
197 data->ReportSetmarks = FALSE;
198 #ifdef HAVE_STRUCT_MTGET_MT_BLKSIZ
199 data->DefaultBlockSize = get.mt_blksiz;
200 #else
201 data->DefaultBlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
202 #endif
203 data->MaximumBlockSize = data->DefaultBlockSize;
204 data->MinimumBlockSize = data->DefaultBlockSize;
205 data->MaximumPartitionCount = 1;
207 return status;
208 #else
209 FIXME( "Not implemented.\n" );
210 return STATUS_NOT_SUPPORTED;
211 #endif
214 /******************************************************************
215 * TAPE_GetMediaParams
217 static NTSTATUS TAPE_GetMediaParams( int fd, TAPE_GET_MEDIA_PARAMETERS *data )
219 #ifdef HAVE_SYS_MTIO_H
220 struct mtget get;
221 NTSTATUS status;
223 TRACE( "fd: %d\n", fd );
225 memset( data, 0, sizeof(TAPE_GET_MEDIA_PARAMETERS) );
227 status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
228 if (status != STATUS_SUCCESS)
229 return status;
231 data->Capacity.QuadPart = 1024 * 1024 * 1024;
232 data->Remaining.QuadPart = 1024 * 1024 * 1024;
233 #ifdef HAVE_STRUCT_MTGET_MT_BLKSIZ
234 data->BlockSize = get.mt_blksiz;
235 #else
236 data->BlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
237 #endif
238 data->PartitionCount = 1;
239 #ifdef HAVE_STRUCT_MTGET_MT_GSTAT
240 data->WriteProtected = (GMT_WR_PROT(get.mt_gstat) != 0);
241 #else
242 data->WriteProtected = 0;
243 #endif
245 return status;
246 #else
247 FIXME( "Not implemented.\n" );
248 return STATUS_NOT_SUPPORTED;
249 #endif
252 /******************************************************************
253 * TAPE_GetPosition
255 static NTSTATUS TAPE_GetPosition( int fd, UINT type, TAPE_GET_POSITION *data )
257 #ifdef HAVE_SYS_MTIO_H
258 struct mtget get;
259 #ifndef HAVE_STRUCT_MTGET_MT_BLKNO
260 struct mtpos pos;
261 #endif
262 NTSTATUS status;
264 TRACE( "fd: %d type: 0x%08x\n", fd, type );
266 memset( data, 0, sizeof(TAPE_GET_POSITION) );
268 status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
269 if (status != STATUS_SUCCESS)
270 return status;
272 #ifndef HAVE_STRUCT_MTGET_MT_BLKNO
273 status = TAPE_GetStatus( ioctl( fd, MTIOCPOS, &pos ) );
274 if (status != STATUS_SUCCESS)
275 return status;
276 #endif
278 switch (type)
280 case TAPE_ABSOLUTE_BLOCK:
281 data->Type = type;
282 data->Partition = get.mt_resid;
283 #ifdef HAVE_STRUCT_MTGET_MT_BLKNO
284 data->OffsetLow = get.mt_blkno;
285 #else
286 data->OffsetLow = pos.mt_blkno;
287 #endif
288 break;
289 case TAPE_LOGICAL_BLOCK:
290 case TAPE_PSEUDO_LOGICAL_BLOCK:
291 WARN( "Positioning type not supported\n" );
292 break;
293 default:
294 ERR( "Unhandled type: 0x%08x\n", type );
295 return STATUS_INVALID_PARAMETER;
298 return status;
299 #else
300 FIXME( "Not implemented.\n" );
301 return STATUS_NOT_SUPPORTED;
302 #endif
305 /******************************************************************
306 * TAPE_Prepare
308 static NTSTATUS TAPE_Prepare( int fd, const TAPE_PREPARE *data )
310 #ifdef HAVE_SYS_MTIO_H
311 struct mtop cmd;
313 TRACE( "fd: %d type: 0x%08x immediate: 0x%02x\n",
314 fd, (int)data->Operation, (int)data->Immediate );
316 switch (data->Operation)
318 #ifdef MTLOAD
319 case TAPE_LOAD:
320 cmd.mt_op = MTLOAD;
321 break;
322 #endif
323 #ifdef MTUNLOAD
324 case TAPE_UNLOAD:
325 cmd.mt_op = MTUNLOAD;
326 break;
327 #endif
328 #ifdef MTRETEN
329 case TAPE_TENSION:
330 cmd.mt_op = MTRETEN;
331 break;
332 #endif
333 #ifdef MTLOCK
334 case TAPE_LOCK:
335 cmd.mt_op = MTLOCK;
336 break;
337 #endif
338 #ifdef MTUNLOCK
339 case TAPE_UNLOCK:
340 cmd.mt_op = MTUNLOCK;
341 break;
342 #endif
343 case TAPE_FORMAT:
344 /* Native ignores this if the drive doesn't support it */
345 return STATUS_SUCCESS;
346 default:
347 ERR( "Unhandled operation: 0x%08x\n", (int)data->Operation );
348 return STATUS_INVALID_PARAMETER;
351 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
352 #else
353 FIXME( "Not implemented.\n" );
354 return STATUS_NOT_SUPPORTED;
355 #endif
358 /******************************************************************
359 * TAPE_SetDriveParams
361 static NTSTATUS TAPE_SetDriveParams( int fd, const TAPE_SET_DRIVE_PARAMETERS *data )
363 #if defined(HAVE_SYS_MTIO_H) && defined(MTCOMPRESSION)
364 struct mtop cmd;
366 TRACE( "fd: %d ECC: 0x%02x, compression: 0x%02x padding: 0x%02x\n",
367 fd, data->ECC, data->Compression, data->DataPadding );
368 TRACE( "setmarks: 0x%02x zonesize: 0x%08x\n",
369 (int)data->ReportSetmarks, (int)data->EOTWarningZoneSize );
371 if (data->ECC || data->DataPadding || data->ReportSetmarks ||
372 data->EOTWarningZoneSize ) WARN( "Setting not supported\n" );
374 cmd.mt_op = MTCOMPRESSION;
375 cmd.mt_count = data->Compression;
377 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
378 #else
379 FIXME( "Not implemented.\n" );
380 return STATUS_NOT_SUPPORTED;
381 #endif
384 /******************************************************************
385 * TAPE_SetMediaParams
387 static NTSTATUS TAPE_SetMediaParams( int fd, const TAPE_SET_MEDIA_PARAMETERS *data )
389 #ifdef HAVE_SYS_MTIO_H
390 struct mtop cmd;
392 TRACE( "fd: %d blocksize: 0x%08x\n", fd, (int)data->BlockSize );
394 cmd.mt_op = MTSETBLK;
395 cmd.mt_count = data->BlockSize;
397 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
398 #else
399 FIXME( "Not implemented.\n" );
400 return STATUS_NOT_SUPPORTED;
401 #endif
404 /******************************************************************
405 * TAPE_SetPosition
407 static NTSTATUS TAPE_SetPosition( int fd, const TAPE_SET_POSITION *data )
409 #ifdef HAVE_SYS_MTIO_H
410 struct mtop cmd;
412 TRACE( "fd: %d method: 0x%08x partition: 0x%08x offset: 0x%s immediate: 0x%02x\n",
413 fd, (int)data->Method, (int)data->Partition, wine_dbgstr_longlong(data->Offset.QuadPart),
414 data->Immediate );
416 if (sizeof(cmd.mt_count) < sizeof(data->Offset.QuadPart) &&
417 (int)data->Offset.QuadPart != data->Offset.QuadPart)
419 ERR("Offset too large or too small\n");
420 return STATUS_INVALID_PARAMETER;
423 switch (data->Method)
425 case TAPE_REWIND:
426 cmd.mt_op = MTREW;
427 break;
428 #ifdef MTSEEK
429 case TAPE_ABSOLUTE_BLOCK:
430 cmd.mt_op = MTSEEK;
431 cmd.mt_count = data->Offset.QuadPart;
432 break;
433 #endif
434 #ifdef MTEOM
435 case TAPE_SPACE_END_OF_DATA:
436 cmd.mt_op = MTEOM;
437 break;
438 #endif
439 case TAPE_SPACE_FILEMARKS:
440 if (data->Offset.QuadPart >= 0) {
441 cmd.mt_op = MTFSF;
442 cmd.mt_count = data->Offset.QuadPart;
444 else {
445 cmd.mt_op = MTBSF;
446 cmd.mt_count = -data->Offset.QuadPart;
448 break;
449 #if defined(MTFSS) && defined(MTBSS)
450 case TAPE_SPACE_SETMARKS:
451 if (data->Offset.QuadPart >= 0) {
452 cmd.mt_op = MTFSS;
453 cmd.mt_count = data->Offset.QuadPart;
455 else {
456 cmd.mt_op = MTBSS;
457 cmd.mt_count = -data->Offset.QuadPart;
459 break;
460 #endif
461 case TAPE_LOGICAL_BLOCK:
462 case TAPE_PSEUDO_LOGICAL_BLOCK:
463 case TAPE_SPACE_RELATIVE_BLOCKS:
464 case TAPE_SPACE_SEQUENTIAL_FMKS:
465 case TAPE_SPACE_SEQUENTIAL_SMKS:
466 WARN( "Positioning method not supported\n" );
467 return STATUS_INVALID_PARAMETER;
468 default:
469 ERR( "Unhandled method: 0x%08x\n", (int)data->Method );
470 return STATUS_INVALID_PARAMETER;
473 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
474 #else
475 FIXME( "Not implemented.\n" );
476 return STATUS_NOT_SUPPORTED;
477 #endif
480 /******************************************************************
481 * TAPE_WriteMarks
483 static NTSTATUS TAPE_WriteMarks( int fd, const TAPE_WRITE_MARKS *data )
485 #ifdef HAVE_SYS_MTIO_H
486 struct mtop cmd;
488 TRACE( "fd: %d type: 0x%08x count: 0x%08x immediate: 0x%02x\n",
489 fd, (int)data->Type, (int)data->Count, data->Immediate );
491 switch (data->Type)
493 #ifdef MTWSM
494 case TAPE_SETMARKS:
495 cmd.mt_op = MTWSM;
496 cmd.mt_count = data->Count;
497 break;
498 #endif
499 case TAPE_FILEMARKS:
500 case TAPE_SHORT_FILEMARKS:
501 case TAPE_LONG_FILEMARKS:
502 cmd.mt_op = MTWEOF;
503 cmd.mt_count = data->Count;
504 break;
505 default:
506 ERR( "Unhandled type: 0x%08x\n", (int)data->Type );
507 return STATUS_INVALID_PARAMETER;
510 return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
511 #else
512 FIXME( "Not implemented.\n" );
513 return STATUS_NOT_SUPPORTED;
514 #endif
517 /******************************************************************
518 * tape_DeviceIoControl
520 NTSTATUS tape_DeviceIoControl( HANDLE device, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
521 IO_STATUS_BLOCK *io, UINT code,
522 void *in_buffer, UINT in_size, void *out_buffer, UINT out_size )
524 DWORD sz = 0;
525 NTSTATUS status = STATUS_INVALID_PARAMETER;
526 int fd, needs_close;
528 TRACE( "%p %s %p %d %p %d %p\n", device, io2str(code),
529 in_buffer, in_size, out_buffer, out_size, io );
531 if ((status = server_get_unix_fd( device, 0, &fd, &needs_close, NULL, NULL )))
532 return status;
534 switch (code)
536 case IOCTL_TAPE_CREATE_PARTITION:
537 status = TAPE_CreatePartition( fd, in_buffer );
538 break;
539 case IOCTL_TAPE_ERASE:
540 status = TAPE_Erase( fd, in_buffer );
541 break;
542 case IOCTL_TAPE_GET_DRIVE_PARAMS:
543 status = TAPE_GetDriveParams( fd, out_buffer );
544 break;
545 case IOCTL_TAPE_GET_MEDIA_PARAMS:
546 status = TAPE_GetMediaParams( fd, out_buffer );
547 break;
548 case IOCTL_TAPE_GET_POSITION:
549 status = TAPE_GetPosition( fd, ((TAPE_GET_POSITION *)in_buffer)->Type,
550 out_buffer );
551 break;
552 case IOCTL_TAPE_GET_STATUS:
553 status = errno_to_status( errno );
554 break;
555 case IOCTL_TAPE_PREPARE:
556 status = TAPE_Prepare( fd, in_buffer );
557 break;
558 case IOCTL_TAPE_SET_DRIVE_PARAMS:
559 status = TAPE_SetDriveParams( fd, in_buffer );
560 break;
561 case IOCTL_TAPE_SET_MEDIA_PARAMS:
562 status = TAPE_SetMediaParams( fd, in_buffer );
563 break;
564 case IOCTL_TAPE_SET_POSITION:
565 status = TAPE_SetPosition( fd, in_buffer );
566 break;
567 case IOCTL_TAPE_WRITE_MARKS:
568 status = TAPE_WriteMarks( fd, in_buffer );
569 break;
571 case IOCTL_TAPE_CHECK_VERIFY:
572 case IOCTL_TAPE_FIND_NEW_DEVICES:
573 break;
574 default:
575 FIXME( "Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
576 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3 );
577 break;
580 if (needs_close) close( fd );
582 if (!NT_ERROR(status))
584 io->Status = status;
585 io->Information = sz;
586 if (event) NtSetEvent( event, NULL );
588 return status;