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