kernel32: FindFirstChangeNotification needs a static IO_STATUS_BLOCK.
[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     data->DefaultBlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
181     data->MaximumBlockSize = data->DefaultBlockSize;
182     data->MinimumBlockSize = data->DefaultBlockSize;
183     data->MaximumPartitionCount = 1;
184
185     return status;
186 #else
187     FIXME( "Not implemented.\n" );
188     return STATUS_NOT_SUPPORTED;
189 #endif
190 }
191
192 /******************************************************************
193  *      TAPE_GetMediaParams
194  */
195 static NTSTATUS TAPE_GetMediaParams( int fd, TAPE_GET_MEDIA_PARAMETERS *data )
196 {
197 #ifdef HAVE_SYS_MTIO_H
198     struct mtget get;
199     NTSTATUS status;
200
201     TRACE( "fd: %d\n", fd );
202
203     memset( data, 0, sizeof(TAPE_GET_MEDIA_PARAMETERS) );
204
205     status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
206     if (status != STATUS_SUCCESS)
207         return status;
208
209     data->Capacity.u.LowPart = 1024 * 1024 * 1024;
210     data->Remaining.u.LowPart = 1024 * 1024 * 1024;
211     data->BlockSize = get.mt_dsreg & MT_ST_BLKSIZE_MASK;
212     data->PartitionCount = 1;
213     data->WriteProtected = GMT_WR_PROT(get.mt_gstat);
214
215     return status;
216 #else
217     FIXME( "Not implemented.\n" );
218     return STATUS_NOT_SUPPORTED;
219 #endif
220 }
221
222 /******************************************************************
223  *      TAPE_GetPosition
224  */
225 static NTSTATUS TAPE_GetPosition( int fd, ULONG type, TAPE_GET_POSITION *data )
226 {
227 #ifdef HAVE_SYS_MTIO_H
228     struct mtget get;
229     struct mtpos pos;
230     NTSTATUS status;
231
232     TRACE( "fd: %d type: 0x%08lx\n", fd, type );
233
234     memset( data, 0, sizeof(TAPE_GET_POSITION) );
235
236     status = TAPE_GetStatus( ioctl( fd, MTIOCGET, &get ) );
237     if (status != STATUS_SUCCESS)
238         return status;
239
240     status = TAPE_GetStatus( ioctl( fd, MTIOCPOS, &pos ) );
241     if (status != STATUS_SUCCESS)
242         return status;
243
244     switch (type)
245     {
246     case TAPE_ABSOLUTE_BLOCK:
247         data->Type = type;
248         data->Partition = get.mt_resid;
249         data->OffsetLow = pos.mt_blkno;
250         break;
251     case TAPE_LOGICAL_BLOCK:
252     case TAPE_PSEUDO_LOGICAL_BLOCK:
253         WARN( "Positioning type not supported\n" );
254         break;
255     default:
256         ERR( "Unhandled type: 0x%08lx\n", type );
257         return STATUS_INVALID_PARAMETER;
258     }
259
260     return status;
261 #else
262     FIXME( "Not implemented.\n" );
263     return STATUS_NOT_SUPPORTED;
264 #endif
265 }
266
267 /******************************************************************
268  *      TAPE_Prepare
269  */
270 static NTSTATUS TAPE_Prepare( int fd, TAPE_PREPARE *data )
271 {
272 #ifdef HAVE_SYS_MTIO_H
273     struct mtop cmd;
274
275     TRACE( "fd: %d type: 0x%08lx immediate: 0x%02x\n",
276            fd, data->Operation, data->Immediate );
277
278     switch (data->Operation)
279     {
280 #ifdef MTLOAD
281     case TAPE_LOAD:
282         cmd.mt_op = MTLOAD;
283         break;
284 #endif
285 #ifdef MTUNLOAD
286     case TAPE_UNLOAD:
287         cmd.mt_op = MTUNLOAD;
288         break;
289 #endif
290 #ifdef MTRETEN
291     case TAPE_TENSION:
292         cmd.mt_op = MTRETEN;
293         break;
294 #endif
295 #ifdef MTLOCK
296     case TAPE_LOCK:
297         cmd.mt_op = MTLOCK;
298         break;
299 #endif
300 #ifdef MTUNLOCK
301     case TAPE_UNLOCK:
302         cmd.mt_op = MTUNLOCK;
303         break;
304 #endif
305     case TAPE_FORMAT:
306         /* Native ignores this if the drive doesn't support it */
307         return STATUS_SUCCESS;
308     default:
309         ERR( "Unhandled operation: 0x%08lx\n", data->Operation );
310         return STATUS_INVALID_PARAMETER;
311     }
312
313     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
314 #else
315     FIXME( "Not implemented.\n" );
316     return STATUS_NOT_SUPPORTED;
317 #endif
318 }
319
320 /******************************************************************
321  *      TAPE_SetDriveParams
322  */
323 static NTSTATUS TAPE_SetDriveParams( int fd, TAPE_SET_DRIVE_PARAMETERS *data )
324 {
325 #ifdef HAVE_SYS_MTIO_H
326     struct mtop cmd;
327
328     TRACE( "fd: %d ECC: 0x%02x, compression: 0x%02x padding: 0x%02x\n",
329             fd, data->ECC, data->Compression, data->DataPadding );
330     TRACE( "setmarks: 0x%02x zonesize: 0x%08lx\n",
331            data->ReportSetmarks, data->EOTWarningZoneSize );
332
333     if (data->ECC || data->DataPadding || data->ReportSetmarks ||
334         data->EOTWarningZoneSize ) WARN( "Setting not supported\n" );
335
336     cmd.mt_op = MTCOMPRESSION;
337     cmd.mt_count = data->Compression;
338
339     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
340 #else
341     FIXME( "Not implemented.\n" );
342     return STATUS_NOT_SUPPORTED;
343 #endif
344 }
345         
346 /******************************************************************
347  *      TAPE_SetMediaParams
348  */
349 static NTSTATUS TAPE_SetMediaParams( int fd, TAPE_SET_MEDIA_PARAMETERS *data )
350 {
351 #ifdef HAVE_SYS_MTIO_H
352     struct mtop cmd;
353
354     TRACE( "fd: %d blocksize: 0x%08lx\n", fd, data->BlockSize );
355     
356     cmd.mt_op = MTSETBLK;
357     cmd.mt_count = data->BlockSize;
358
359     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
360 #else
361     FIXME( "Not implemented.\n" );
362     return STATUS_NOT_SUPPORTED;
363 #endif
364 }
365         
366 /******************************************************************
367  *      TAPE_SetPosition
368  */
369 static NTSTATUS TAPE_SetPosition( int fd, TAPE_SET_POSITION *data )
370 {
371 #ifdef HAVE_SYS_MTIO_H
372     struct mtop cmd;
373
374     TRACE( "fd: %d method: 0x%08lx partition: 0x%08lx offset: 0x%08lx immediate: 0x%02x\n",
375            fd, data->Method, data->Partition, data->Offset.u.LowPart, data->Immediate );
376
377     if (data->Offset.u.HighPart > 0)
378         return STATUS_INVALID_PARAMETER;
379
380     switch (data->Method)
381     {
382     case TAPE_REWIND:
383         cmd.mt_op = MTREW;
384         break;
385 #ifdef MTSEEK
386     case TAPE_ABSOLUTE_BLOCK:
387         cmd.mt_op = MTSEEK;
388         cmd.mt_count = data->Offset.u.LowPart;
389         break;
390 #endif
391 #ifdef MTEOM
392     case TAPE_SPACE_END_OF_DATA:
393         cmd.mt_op = MTEOM;
394         break;
395 #endif
396     case TAPE_SPACE_FILEMARKS:
397         if (data->Offset.u.LowPart >= 0) {
398             cmd.mt_op = MTFSF;
399             cmd.mt_count = data->Offset.u.LowPart;
400         }
401         else {
402             cmd.mt_op = MTBSF;
403             cmd.mt_count = -data->Offset.u.LowPart;
404         }
405         break;
406     case TAPE_SPACE_SETMARKS:
407         if (data->Offset.u.LowPart >= 0) {
408             cmd.mt_op = MTFSS;
409             cmd.mt_count = data->Offset.u.LowPart;
410         }
411         else {
412             cmd.mt_op = MTBSS;
413             cmd.mt_count = -data->Offset.u.LowPart;
414         }
415         break;
416     case TAPE_LOGICAL_BLOCK:
417     case TAPE_PSEUDO_LOGICAL_BLOCK:
418     case TAPE_SPACE_RELATIVE_BLOCKS:
419     case TAPE_SPACE_SEQUENTIAL_FMKS:
420     case TAPE_SPACE_SEQUENTIAL_SMKS:
421         WARN( "Positioning method not supported\n" );
422         return STATUS_INVALID_PARAMETER;
423     default:
424         ERR( "Unhandled method: 0x%08lx\n", data->Method );
425         return STATUS_INVALID_PARAMETER;
426     }
427
428     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
429 #else
430     FIXME( "Not implemented.\n" );
431     return STATUS_NOT_SUPPORTED;
432 #endif
433 }
434
435 /******************************************************************
436  *      TAPE_WriteMarks
437  */
438 static NTSTATUS TAPE_WriteMarks( int fd, TAPE_WRITE_MARKS *data )
439 {
440 #ifdef HAVE_SYS_MTIO_H
441     struct mtop cmd;
442
443     TRACE( "fd: %d type: 0x%08lx count: 0x%08lx immediate: 0x%02x\n",
444            fd, data->Type, data->Count, data->Immediate );
445
446     switch (data->Type)
447     {
448 #ifdef MTWSM
449     case TAPE_SETMARKS:
450         cmd.mt_op = MTWSM;
451         cmd.mt_count = data->Count;
452         break;
453 #endif
454     case TAPE_FILEMARKS:
455     case TAPE_SHORT_FILEMARKS:
456     case TAPE_LONG_FILEMARKS:
457         cmd.mt_op = MTWEOF;
458         cmd.mt_count = data->Count;
459         break;
460     default:
461         ERR( "Unhandled type: 0x%08lx\n", data->Type );
462         return STATUS_INVALID_PARAMETER;
463     }
464
465     return TAPE_GetStatus( ioctl( fd, MTIOCTOP, &cmd ) );
466 #else
467     FIXME( "Not implemented.\n" );
468     return STATUS_NOT_SUPPORTED;
469 #endif
470 }
471
472 /******************************************************************
473  *              TAPE_DeviceIoControl
474  *
475  * SEE ALSO
476  *   NtDeviceIoControl.
477  */
478 NTSTATUS TAPE_DeviceIoControl( HANDLE device, HANDLE event,
479     PIO_APC_ROUTINE apc, PVOID apc_user, PIO_STATUS_BLOCK io_status,
480     ULONG io_control, LPVOID in_buffer, DWORD in_size,
481     LPVOID out_buffer, DWORD out_size )
482 {
483     DWORD sz = 0;
484     NTSTATUS status = STATUS_INVALID_PARAMETER;
485     int fd;
486
487     TRACE( "%p %s %p %ld %p %ld %p\n", device, io2str(io_control),
488            in_buffer, in_size, out_buffer, out_size, io_status );
489
490     io_status->Information = 0;
491
492     if ((status = wine_server_handle_to_fd( device, 0, &fd, NULL )))
493         goto error;
494
495     switch (io_control)
496     {
497     case IOCTL_TAPE_CREATE_PARTITION:
498         status = TAPE_CreatePartition( fd, (TAPE_CREATE_PARTITION *)in_buffer );
499         break;
500     case IOCTL_TAPE_ERASE:
501         status = TAPE_Erase( fd, (TAPE_ERASE *)in_buffer );
502         break;
503     case IOCTL_TAPE_GET_DRIVE_PARAMS:
504         status = TAPE_GetDriveParams( fd, (TAPE_GET_DRIVE_PARAMETERS *)out_buffer );
505         break;
506     case IOCTL_TAPE_GET_MEDIA_PARAMS:
507         status = TAPE_GetMediaParams( fd, (TAPE_GET_MEDIA_PARAMETERS *)out_buffer );
508         break;
509     case IOCTL_TAPE_GET_POSITION:
510         status = TAPE_GetPosition( fd, ((TAPE_GET_POSITION *)in_buffer)->Type,
511                                    (TAPE_GET_POSITION *)out_buffer );
512         break;
513     case IOCTL_TAPE_GET_STATUS:
514         status = FILE_GetNtStatus();
515         break;
516     case IOCTL_TAPE_PREPARE:
517         status = TAPE_Prepare( fd, (TAPE_PREPARE *)in_buffer );
518         break;
519     case IOCTL_TAPE_SET_DRIVE_PARAMS:
520         status = TAPE_SetDriveParams( fd, (TAPE_SET_DRIVE_PARAMETERS *)in_buffer );
521         break;
522     case IOCTL_TAPE_SET_MEDIA_PARAMS:
523         status = TAPE_SetMediaParams( fd, (TAPE_SET_MEDIA_PARAMETERS *)in_buffer );
524         break;
525     case IOCTL_TAPE_SET_POSITION:
526         status = TAPE_SetPosition( fd, (TAPE_SET_POSITION *)in_buffer );
527         break;
528     case IOCTL_TAPE_WRITE_MARKS:
529         status = TAPE_WriteMarks( fd, (TAPE_WRITE_MARKS *)in_buffer );
530         break;
531
532     case IOCTL_TAPE_CHECK_VERIFY:
533     case IOCTL_TAPE_FIND_NEW_DEVICES:
534         break;
535     default:
536         FIXME( "Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
537                io_control, io_control >> 16, (io_control >> 14) & 3,
538                (io_control >> 2) & 0xfff, io_control & 3 );
539         break;
540     }
541
542     wine_server_release_fd( device, fd );
543
544 error:
545     io_status->u.Status = status;
546     io_status->Information = sz;
547     if (event) NtSetEvent( event, NULL );
548     return status;
549 }