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