ntdll: Use struct mtget.mt_blksiz on systems featuring this.
[wine] / dlls / ntdll / tape.c
1 /*
2  * TAPE support
3  *
4  * Copyright 2006 Hans Leidekker
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #ifdef HAVE_SYS_IOCTL_H
27 #include <sys/ioctl.h>
28 #endif
29 #ifdef HAVE_SYS_MTIO_H
30 #include <sys/mtio.h>
31 #endif
32
33 /* FreeBSD, for example, has MTCOMP instead of MTCOMPRESSION. */
34 #if !defined(MTCOMPRESSION) && defined(MTCOMP)
35 #define MTCOMPRESSION MTCOMP
36 #endif
37
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "ntstatus.h"
41 #define WIN32_NO_STATUS
42 #include "windef.h"
43 #include "winternl.h"
44 #include "winioctl.h"
45 #include "ddk/ntddtape.h"
46 #include "ntdll_misc.h"
47 #include "wine/server.h"
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(tape);
51
52 static const char *io2str( DWORD io )
53 {
54     switch (io)
55     {
56 #define X(x)    case (x): return #x;
57     X(IOCTL_TAPE_CHECK_VERIFY);
58     X(IOCTL_TAPE_CREATE_PARTITION);
59     X(IOCTL_TAPE_ERASE);
60     X(IOCTL_TAPE_FIND_NEW_DEVICES);
61     X(IOCTL_TAPE_GET_DRIVE_PARAMS);
62     X(IOCTL_TAPE_GET_MEDIA_PARAMS);
63     X(IOCTL_TAPE_GET_POSITION);
64     X(IOCTL_TAPE_GET_STATUS);
65     X(IOCTL_TAPE_PREPARE);
66     X(IOCTL_TAPE_SET_DRIVE_PARAMS);
67     X(IOCTL_TAPE_SET_MEDIA_PARAMS);
68     X(IOCTL_TAPE_SET_POSITION);
69     X(IOCTL_TAPE_WRITE_MARKS);
70 #undef X
71     default: { static char tmp[32]; sprintf(tmp, "IOCTL_TAPE_%ld\n", io); return tmp; }
72     }
73 }
74
75 /******************************************************************
76  *      TAPE_GetStatus
77  */
78 static NTSTATUS TAPE_GetStatus( int error )
79 {
80     if (!error) return STATUS_SUCCESS;
81     return FILE_GetNtStatus();
82 }
83
84 /******************************************************************
85  *      TAPE_CreatePartition
86  */
87 static NTSTATUS TAPE_CreatePartition( int fd, TAPE_CREATE_PARTITION *data )
88 {
89 #ifdef HAVE_SYS_MTIO_H
90     struct mtop cmd;
91
92     TRACE( "fd: %d method: 0x%08lx count: 0x%08lx size: 0x%08lx\n",
93            fd, data->Method, data->Count, data->Size );
94
95     if (data->Count > 1)
96     {
97         WARN( "Creating more than 1 partition is not supported\n" );
98         return STATUS_INVALID_PARAMETER;
99     }
100
101     switch (data->Method)
102     {
103 #ifdef MTMKPART
104     case TAPE_FIXED_PARTITIONS:
105     case TAPE_SELECT_PARTITIONS:
106         cmd.mt_op = MTMKPART;
107         cmd.mt_count = 0;
108         break;
109     case TAPE_INITIATOR_PARTITIONS:
110         cmd.mt_op = MTMKPART;
111         cmd.mt_count = data->Size;
112         break;
113 #endif
114     default:
115         ERR( "Unhandled method: 0x%08lx\n", data->Method );
116         return STATUS_INVALID_PARAMETER;
117     }
118
119     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
120 #else
121     FIXME( "Not implemented.\n" );
122     return STATUS_NOT_SUPPORTED;
123 #endif
124 }
125
126 /******************************************************************
127  *      TAPE_Erase
128  */
129 static NTSTATUS TAPE_Erase( int fd, TAPE_ERASE *data )
130 {
131 #ifdef HAVE_SYS_MTIO_H
132     struct mtop cmd;
133
134     TRACE( "fd: %d type: 0x%08lx immediate: 0x%02x\n",
135            fd, data->Type, data->Immediate );
136
137     switch (data->Type)
138     {
139     case TAPE_ERASE_LONG:
140         cmd.mt_op = MTERASE;
141         cmd.mt_count = 1;
142         break;
143     case TAPE_ERASE_SHORT:
144         cmd.mt_op = MTERASE;
145         cmd.mt_count = 0;
146         break;
147     default:
148         ERR( "Unhandled type: 0x%08lx\n", data->Type );
149         return STATUS_INVALID_PARAMETER;
150     }
151
152     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
153 #else
154     FIXME( "Not implemented.\n" );
155     return STATUS_NOT_SUPPORTED;
156 #endif
157 }
158
159 /******************************************************************
160  *      TAPE_GetDriveParams
161  */
162 static NTSTATUS TAPE_GetDriveParams( int fd, TAPE_GET_DRIVE_PARAMETERS *data )
163 {
164 #ifdef HAVE_SYS_MTIO_H
165     struct mtget get;
166     NTSTATUS status;
167
168     TRACE( "fd: %d\n", fd );
169
170     memset( data, 0, sizeof(TAPE_GET_DRIVE_PARAMETERS) );
171
172     status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
173     if (status != STATUS_SUCCESS)
174         return status;
175
176     data->ECC = FALSE;
177     data->Compression = FALSE;
178     data->DataPadding = FALSE;
179     data->ReportSetmarks = FALSE;
180 #ifdef HAVE_STRUCT_MTGET_MT_BLKSIZ
181     data->DefaultBlockSize = get.mt_blksiz;
182 #else
183     data->DefaultBlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
184 #endif
185     data->MaximumBlockSize = data->DefaultBlockSize;
186     data->MinimumBlockSize = data->DefaultBlockSize;
187     data->MaximumPartitionCount = 1;
188
189     return status;
190 #else
191     FIXME( "Not implemented.\n" );
192     return STATUS_NOT_SUPPORTED;
193 #endif
194 }
195
196 /******************************************************************
197  *      TAPE_GetMediaParams
198  */
199 static NTSTATUS TAPE_GetMediaParams( int fd, TAPE_GET_MEDIA_PARAMETERS *data )
200 {
201 #ifdef HAVE_SYS_MTIO_H
202     struct mtget get;
203     NTSTATUS status;
204
205     TRACE( "fd: %d\n", fd );
206
207     memset( data, 0, sizeof(TAPE_GET_MEDIA_PARAMETERS) );
208
209     status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
210     if (status != STATUS_SUCCESS)
211         return status;
212
213     data->Capacity.u.LowPart = 1024 * 1024 * 1024;
214     data->Remaining.u.LowPart = 1024 * 1024 * 1024;
215 #ifdef HAVE_STRUCT_MTGET_MT_BLKSIZ
216     data->BlockSize = get.mt_blksiz;
217 #else
218     data->BlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
219 #endif
220     data->PartitionCount = 1;
221 #ifdef HAVE_STRUCT_MTGET_GSTAT
222     data->WriteProtected = GMT_WR_PROT(get.mt_gstat);
223 #else
224     data->WriteProtected = 0;
225 #endif
226
227     return status;
228 #else
229     FIXME( "Not implemented.\n" );
230     return STATUS_NOT_SUPPORTED;
231 #endif
232 }
233
234 /******************************************************************
235  *      TAPE_GetPosition
236  */
237 static NTSTATUS TAPE_GetPosition( int fd, ULONG type, TAPE_GET_POSITION *data )
238 {
239 #ifdef HAVE_SYS_MTIO_H
240     struct mtget get;
241     struct mtpos pos;
242     NTSTATUS status;
243
244     TRACE( "fd: %d type: 0x%08lx\n", fd, type );
245
246     memset( data, 0, sizeof(TAPE_GET_POSITION) );
247
248     status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
249     if (status != STATUS_SUCCESS)
250         return status;
251
252     status = TAPE_GetStatus( ioctl( fd, MTIOCPOS, &pos ) );
253     if (status != STATUS_SUCCESS)
254         return status;
255
256     switch (type)
257     {
258     case TAPE_ABSOLUTE_BLOCK:
259         data->Type = type;
260         data->Partition = get.mt_resid;
261         data->OffsetLow = pos.mt_blkno;
262         break;
263     case TAPE_LOGICAL_BLOCK:
264     case TAPE_PSEUDO_LOGICAL_BLOCK:
265         WARN( "Positioning type not supported\n" );
266         break;
267     default:
268         ERR( "Unhandled type: 0x%08lx\n", type );
269         return STATUS_INVALID_PARAMETER;
270     }
271
272     return status;
273 #else
274     FIXME( "Not implemented.\n" );
275     return STATUS_NOT_SUPPORTED;
276 #endif
277 }
278
279 /******************************************************************
280  *      TAPE_Prepare
281  */
282 static NTSTATUS TAPE_Prepare( int fd, TAPE_PREPARE *data )
283 {
284 #ifdef HAVE_SYS_MTIO_H
285     struct mtop cmd;
286
287     TRACE( "fd: %d type: 0x%08lx immediate: 0x%02x\n",
288            fd, data->Operation, data->Immediate );
289
290     switch (data->Operation)
291     {
292 #ifdef MTLOAD
293     case TAPE_LOAD:
294         cmd.mt_op = MTLOAD;
295         break;
296 #endif
297 #ifdef MTUNLOAD
298     case TAPE_UNLOAD:
299         cmd.mt_op = MTUNLOAD;
300         break;
301 #endif
302 #ifdef MTRETEN
303     case TAPE_TENSION:
304         cmd.mt_op = MTRETEN;
305         break;
306 #endif
307 #ifdef MTLOCK
308     case TAPE_LOCK:
309         cmd.mt_op = MTLOCK;
310         break;
311 #endif
312 #ifdef MTUNLOCK
313     case TAPE_UNLOCK:
314         cmd.mt_op = MTUNLOCK;
315         break;
316 #endif
317     case TAPE_FORMAT:
318         /* Native ignores this if the drive doesn't support it */
319         return STATUS_SUCCESS;
320     default:
321         ERR( "Unhandled operation: 0x%08lx\n", data->Operation );
322         return STATUS_INVALID_PARAMETER;
323     }
324
325     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
326 #else
327     FIXME( "Not implemented.\n" );
328     return STATUS_NOT_SUPPORTED;
329 #endif
330 }
331
332 /******************************************************************
333  *      TAPE_SetDriveParams
334  */
335 static NTSTATUS TAPE_SetDriveParams( int fd, TAPE_SET_DRIVE_PARAMETERS *data )
336 {
337 #ifdef HAVE_SYS_MTIO_H
338     struct mtop cmd;
339
340     TRACE( "fd: %d ECC: 0x%02x, compression: 0x%02x padding: 0x%02x\n",
341             fd, data->ECC, data->Compression, data->DataPadding );
342     TRACE( "setmarks: 0x%02x zonesize: 0x%08lx\n",
343            data->ReportSetmarks, data->EOTWarningZoneSize );
344
345     if (data->ECC || data->DataPadding || data->ReportSetmarks ||
346         data->EOTWarningZoneSize ) WARN( "Setting not supported\n" );
347
348     cmd.mt_op = MTCOMPRESSION;
349     cmd.mt_count = data->Compression;
350
351     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
352 #else
353     FIXME( "Not implemented.\n" );
354     return STATUS_NOT_SUPPORTED;
355 #endif
356 }
357         
358 /******************************************************************
359  *      TAPE_SetMediaParams
360  */
361 static NTSTATUS TAPE_SetMediaParams( int fd, TAPE_SET_MEDIA_PARAMETERS *data )
362 {
363 #ifdef HAVE_SYS_MTIO_H
364     struct mtop cmd;
365
366     TRACE( "fd: %d blocksize: 0x%08lx\n", fd, data->BlockSize );
367     
368     cmd.mt_op = MTSETBLK;
369     cmd.mt_count = data->BlockSize;
370
371     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
372 #else
373     FIXME( "Not implemented.\n" );
374     return STATUS_NOT_SUPPORTED;
375 #endif
376 }
377         
378 /******************************************************************
379  *      TAPE_SetPosition
380  */
381 static NTSTATUS TAPE_SetPosition( int fd, TAPE_SET_POSITION *data )
382 {
383 #ifdef HAVE_SYS_MTIO_H
384     struct mtop cmd;
385
386     TRACE( "fd: %d method: 0x%08lx partition: 0x%08lx offset: 0x%08lx immediate: 0x%02x\n",
387            fd, data->Method, data->Partition, data->Offset.u.LowPart, data->Immediate );
388
389     if (data->Offset.u.HighPart > 0)
390         return STATUS_INVALID_PARAMETER;
391
392     switch (data->Method)
393     {
394     case TAPE_REWIND:
395         cmd.mt_op = MTREW;
396         break;
397 #ifdef MTSEEK
398     case TAPE_ABSOLUTE_BLOCK:
399         cmd.mt_op = MTSEEK;
400         cmd.mt_count = data->Offset.u.LowPart;
401         break;
402 #endif
403 #ifdef MTEOM
404     case TAPE_SPACE_END_OF_DATA:
405         cmd.mt_op = MTEOM;
406         break;
407 #endif
408     case TAPE_SPACE_FILEMARKS:
409         if (data->Offset.u.LowPart >= 0) {
410             cmd.mt_op = MTFSF;
411             cmd.mt_count = data->Offset.u.LowPart;
412         }
413         else {
414             cmd.mt_op = MTBSF;
415             cmd.mt_count = -data->Offset.u.LowPart;
416         }
417         break;
418     case TAPE_SPACE_SETMARKS:
419         if (data->Offset.u.LowPart >= 0) {
420             cmd.mt_op = MTFSS;
421             cmd.mt_count = data->Offset.u.LowPart;
422         }
423         else {
424             cmd.mt_op = MTBSS;
425             cmd.mt_count = -data->Offset.u.LowPart;
426         }
427         break;
428     case TAPE_LOGICAL_BLOCK:
429     case TAPE_PSEUDO_LOGICAL_BLOCK:
430     case TAPE_SPACE_RELATIVE_BLOCKS:
431     case TAPE_SPACE_SEQUENTIAL_FMKS:
432     case TAPE_SPACE_SEQUENTIAL_SMKS:
433         WARN( "Positioning method not supported\n" );
434         return STATUS_INVALID_PARAMETER;
435     default:
436         ERR( "Unhandled method: 0x%08lx\n", data->Method );
437         return STATUS_INVALID_PARAMETER;
438     }
439
440     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
441 #else
442     FIXME( "Not implemented.\n" );
443     return STATUS_NOT_SUPPORTED;
444 #endif
445 }
446
447 /******************************************************************
448  *      TAPE_WriteMarks
449  */
450 static NTSTATUS TAPE_WriteMarks( int fd, TAPE_WRITE_MARKS *data )
451 {
452 #ifdef HAVE_SYS_MTIO_H
453     struct mtop cmd;
454
455     TRACE( "fd: %d type: 0x%08lx count: 0x%08lx immediate: 0x%02x\n",
456            fd, data->Type, data->Count, data->Immediate );
457
458     switch (data->Type)
459     {
460 #ifdef MTWSM
461     case TAPE_SETMARKS:
462         cmd.mt_op = MTWSM;
463         cmd.mt_count = data->Count;
464         break;
465 #endif
466     case TAPE_FILEMARKS:
467     case TAPE_SHORT_FILEMARKS:
468     case TAPE_LONG_FILEMARKS:
469         cmd.mt_op = MTWEOF;
470         cmd.mt_count = data->Count;
471         break;
472     default:
473         ERR( "Unhandled type: 0x%08lx\n", data->Type );
474         return STATUS_INVALID_PARAMETER;
475     }
476
477     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
478 #else
479     FIXME( "Not implemented.\n" );
480     return STATUS_NOT_SUPPORTED;
481 #endif
482 }
483
484 /******************************************************************
485  *              TAPE_DeviceIoControl
486  *
487  * SEE ALSO
488  *   NtDeviceIoControl.
489  */
490 NTSTATUS TAPE_DeviceIoControl( HANDLE device, HANDLE event,
491     PIO_APC_ROUTINE apc, PVOID apc_user, PIO_STATUS_BLOCK io_status,
492     ULONG io_control, LPVOID in_buffer, DWORD in_size,
493     LPVOID out_buffer, DWORD out_size )
494 {
495     DWORD sz = 0;
496     NTSTATUS status = STATUS_INVALID_PARAMETER;
497     int fd;
498
499     TRACE( "%p %s %p %ld %p %ld %p\n", device, io2str(io_control),
500            in_buffer, in_size, out_buffer, out_size, io_status );
501
502     io_status->Information = 0;
503
504     if ((status = wine_server_handle_to_fd( device, 0, &fd, NULL )))
505         goto error;
506
507     switch (io_control)
508     {
509     case IOCTL_TAPE_CREATE_PARTITION:
510         status = TAPE_CreatePartition( fd, (TAPE_CREATE_PARTITION *)in_buffer );
511         break;
512     case IOCTL_TAPE_ERASE:
513         status = TAPE_Erase( fd, (TAPE_ERASE *)in_buffer );
514         break;
515     case IOCTL_TAPE_GET_DRIVE_PARAMS:
516         status = TAPE_GetDriveParams( fd, (TAPE_GET_DRIVE_PARAMETERS *)out_buffer );
517         break;
518     case IOCTL_TAPE_GET_MEDIA_PARAMS:
519         status = TAPE_GetMediaParams( fd, (TAPE_GET_MEDIA_PARAMETERS *)out_buffer );
520         break;
521     case IOCTL_TAPE_GET_POSITION:
522         status = TAPE_GetPosition( fd, ((TAPE_GET_POSITION *)in_buffer)->Type,
523                                    (TAPE_GET_POSITION *)out_buffer );
524         break;
525     case IOCTL_TAPE_GET_STATUS:
526         status = FILE_GetNtStatus();
527         break;
528     case IOCTL_TAPE_PREPARE:
529         status = TAPE_Prepare( fd, (TAPE_PREPARE *)in_buffer );
530         break;
531     case IOCTL_TAPE_SET_DRIVE_PARAMS:
532         status = TAPE_SetDriveParams( fd, (TAPE_SET_DRIVE_PARAMETERS *)in_buffer );
533         break;
534     case IOCTL_TAPE_SET_MEDIA_PARAMS:
535         status = TAPE_SetMediaParams( fd, (TAPE_SET_MEDIA_PARAMETERS *)in_buffer );
536         break;
537     case IOCTL_TAPE_SET_POSITION:
538         status = TAPE_SetPosition( fd, (TAPE_SET_POSITION *)in_buffer );
539         break;
540     case IOCTL_TAPE_WRITE_MARKS:
541         status = TAPE_WriteMarks( fd, (TAPE_WRITE_MARKS *)in_buffer );
542         break;
543
544     case IOCTL_TAPE_CHECK_VERIFY:
545     case IOCTL_TAPE_FIND_NEW_DEVICES:
546         break;
547     default:
548         FIXME( "Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
549                io_control, io_control >> 16, (io_control >> 14) & 3,
550                (io_control >> 2) & 0xfff, io_control & 3 );
551         break;
552     }
553
554     wine_server_release_fd( device, fd );
555
556 error:
557     io_status->u.Status = status;
558     io_status->Information = sz;
559     if (event) NtSetEvent( event, NULL );
560     return status;
561 }