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