500955b5083e6755f2c2459cfcadb1a194c9553b
[people/sha0/winvblock.git] / src / httpdisk_util / httpdisk.c
1 /*
2     HTTP Virtual Disk.
3     Copyright (C) 2006 Bo Brantén.
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12     You should have received a copy of the GNU General Public License
13     along with this program; if not, write to the Free Software
14     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15 */
16
17 #include <windows.h>
18 #include <winioctl.h>
19 #include <winsock2.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "httpdisk.h"
23
24 int
25 HttpDiskSyntax (
26   void
27  )
28 {
29   fprintf ( stderr, "syntax:\n" );
30   fprintf ( stderr, "httpdisk /mount  <devicenumber> <url> [/cd] <drive:>\n" );
31   fprintf ( stderr, "httpdisk /umount <drive:>\n" );
32   fprintf ( stderr, "\n" );
33   fprintf ( stderr, "example:\n" );
34   fprintf ( stderr,
35             "httpdisk /mount  0 http://server.domain.com/path/diskimage.img d:\n" );
36   fprintf ( stderr,
37             "httpdisk /mount  1 http://server.domain.com/path/cdimage.iso /cd e:\n" );
38   fprintf ( stderr, "...\n" );
39   fprintf ( stderr, "httpdisk /umount d:\n" );
40   fprintf ( stderr, "httpdisk /umount e:\n" );
41
42   return -1;
43 }
44
45 void
46 PrintLastError (
47   char *Prefix
48  )
49 {
50   LPVOID lpMsgBuf;
51
52   FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
53                   FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError (  ), 0,
54                   ( LPTSTR ) & lpMsgBuf, 0, NULL );
55
56   fprintf ( stderr, "%s: %s", Prefix, ( LPTSTR ) lpMsgBuf );
57
58   LocalFree ( lpMsgBuf );
59 }
60
61 int
62 HttpDiskMount (
63   int DeviceNumber,
64   PHTTP_DISK_INFORMATION HttpDiskInformation,
65   char DriveLetter,
66   BOOLEAN CdImage
67  )
68 {
69   char VolumeName[] = "\\\\.\\ :";
70   char DeviceName[255];
71   HANDLE Device;
72   DWORD BytesReturned;
73
74   VolumeName[4] = DriveLetter;
75
76   Device =
77     CreateFile ( VolumeName, GENERIC_READ | GENERIC_WRITE,
78                  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
79                  FILE_FLAG_NO_BUFFERING, NULL );
80
81   if ( Device != INVALID_HANDLE_VALUE )
82     {
83       SetLastError ( ERROR_BUSY );
84       PrintLastError ( &VolumeName[4] );
85       return -1;
86     }
87
88   if ( CdImage )
89     {
90       sprintf ( DeviceName, DEVICE_NAME_PREFIX "Cd" "%u", DeviceNumber );
91     }
92   else
93     {
94       sprintf ( DeviceName, DEVICE_NAME_PREFIX "Disk" "%u", DeviceNumber );
95     }
96
97   if ( !DefineDosDevice ( DDD_RAW_TARGET_PATH, &VolumeName[4], DeviceName ) )
98     {
99       PrintLastError ( &VolumeName[4] );
100       return -1;
101     }
102
103   Device =
104     CreateFile ( VolumeName, GENERIC_READ | GENERIC_WRITE,
105                  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
106                  FILE_FLAG_NO_BUFFERING, NULL );
107
108   if ( Device == INVALID_HANDLE_VALUE )
109     {
110       PrintLastError ( &VolumeName[4] );
111       DefineDosDevice ( DDD_REMOVE_DEFINITION, &VolumeName[4], NULL );
112       return -1;
113     }
114
115   if ( !DeviceIoControl
116        ( Device, IOCTL_HTTP_DISK_CONNECT, HttpDiskInformation,
117          sizeof ( HTTP_DISK_INFORMATION ) +
118          HttpDiskInformation->FileNameLength - 1, NULL, 0, &BytesReturned,
119          NULL ) )
120     {
121       PrintLastError ( "HttpDisk" );
122       DefineDosDevice ( DDD_REMOVE_DEFINITION, &VolumeName[4], NULL );
123       return -1;
124     }
125
126   return 0;
127 }
128
129 int
130 HttpDiskUmount (
131   char DriveLetter
132  )
133 {
134   char VolumeName[] = "\\\\.\\ :";
135   HANDLE Device;
136   DWORD BytesReturned;
137
138   VolumeName[4] = DriveLetter;
139
140   Device =
141     CreateFile ( VolumeName, GENERIC_READ | GENERIC_WRITE,
142                  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
143                  FILE_FLAG_NO_BUFFERING, NULL );
144
145   if ( Device == INVALID_HANDLE_VALUE )
146     {
147       PrintLastError ( &VolumeName[4] );
148       return -1;
149     }
150
151   if ( !DeviceIoControl
152        ( Device, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned, NULL ) )
153     {
154       PrintLastError ( &VolumeName[4] );
155       return -1;
156     }
157
158   if ( !DeviceIoControl
159        ( Device, IOCTL_HTTP_DISK_DISCONNECT, NULL, 0, NULL, 0, &BytesReturned,
160          NULL ) )
161     {
162       PrintLastError ( "HttpDisk" );
163       return -1;
164     }
165
166   if ( !DeviceIoControl
167        ( Device, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &BytesReturned,
168          NULL ) )
169     {
170       PrintLastError ( &VolumeName[4] );
171       return -1;
172     }
173
174   if ( !DeviceIoControl
175        ( Device, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &BytesReturned,
176          NULL ) )
177     {
178       PrintLastError ( &VolumeName[4] );
179       return -1;
180     }
181
182   CloseHandle ( Device );
183
184   if ( !DefineDosDevice ( DDD_REMOVE_DEFINITION, &VolumeName[4], NULL ) )
185     {
186       PrintLastError ( &VolumeName[4] );
187       return -1;
188     }
189
190   return 0;
191 }
192
193 int __cdecl
194 main (
195   int argc,
196   char *argv[]
197  )
198 {
199   char *Command;
200   int DeviceNumber;
201   char *Url;
202   char *Option;
203   char DriveLetter;
204   BOOLEAN CdImage;
205   PHTTP_DISK_INFORMATION HttpDiskInformation;
206   char *FileName;
207   char *PortStr;
208   struct hostent *HostEnt;
209   WSADATA wsaData;
210
211   Command = argv[1];
212
213   if ( ( argc == 5 || argc == 6 ) && !strcmp ( Command, "/mount" ) )
214     {
215       DeviceNumber = atoi ( argv[2] );
216       Url = argv[3];
217
218       if ( argc > 5 )
219         {
220           Option = argv[4];
221           DriveLetter = argv[5][0];
222
223           if ( !strcmp ( Option, "/cd" ) )
224             {
225               CdImage = TRUE;
226             }
227           else
228             {
229               return HttpDiskSyntax (  );
230             }
231         }
232       else
233         {
234           Option = NULL;
235           DriveLetter = argv[4][0];
236           CdImage = FALSE;
237         }
238
239       HttpDiskInformation =
240         malloc ( sizeof ( HTTP_DISK_INFORMATION ) + strlen ( Url ) );
241
242       memset ( HttpDiskInformation, 0,
243                sizeof ( HTTP_DISK_INFORMATION ) + strlen ( Url ) );
244
245       if ( strstr ( Url, "//" ) )
246         {
247           if ( strlen ( Url ) > 7 && !strncmp ( Url, "http://", 7 ) )
248             {
249               Url += 7;
250             }
251           else
252             {
253               fprintf ( stderr, "Invalid protocol.\n" );
254               return -1;
255             }
256         }
257
258       FileName = strstr ( Url, "/" );
259
260       if ( !FileName )
261         {
262           fprintf ( stderr, "%s: Invalid url.\n", Url );
263           return -1;
264         }
265
266       strcpy ( HttpDiskInformation->FileName, FileName );
267
268       HttpDiskInformation->FileNameLength =
269         ( USHORT ) strlen ( HttpDiskInformation->FileName );
270
271       *FileName = '\0';
272
273       PortStr = strstr ( Url, ":" );
274
275       if ( PortStr )
276         {
277           HttpDiskInformation->Port =
278             htons ( ( USHORT ) atoi ( PortStr + 1 ) );
279
280           if ( HttpDiskInformation->Port == 0 )
281             {
282               fprintf ( stderr, "%s: Invalid port.\n", PortStr + 1 );
283               return -1;
284             }
285
286           *PortStr = '\0';
287         }
288       else
289         {
290           HttpDiskInformation->Port = htons ( 80 );
291         }
292
293       HttpDiskInformation->HostNameLength = ( USHORT ) strlen ( Url );
294
295       if ( HttpDiskInformation->HostNameLength > 255 )
296         {
297           fprintf ( stderr, "%s: Host name to long.\n", Url );
298           return -1;
299         }
300
301       strcpy ( HttpDiskInformation->HostName, Url );
302
303       HttpDiskInformation->Address = inet_addr ( Url );
304
305       if ( HttpDiskInformation->Address == INADDR_NONE )
306         {
307           if ( WSAStartup ( MAKEWORD ( 1, 1 ), &wsaData ) != 0 )
308             {
309               PrintLastError ( "HttpDisk" );
310               return -1;
311             }
312
313           HostEnt = gethostbyname ( Url );
314
315           if ( !HostEnt )
316             {
317               PrintLastError ( Url );
318               return -1;
319             }
320
321           HttpDiskInformation->Address =
322             ( ( struct in_addr * )HostEnt->h_addr )->s_addr;
323         }
324
325       return HttpDiskMount ( DeviceNumber, HttpDiskInformation, DriveLetter,
326                              CdImage );
327     }
328   else if ( argc == 3 && !strcmp ( Command, "/umount" ) )
329     {
330       DriveLetter = argv[2][0];
331       return HttpDiskUmount ( DriveLetter );
332     }
333   else
334     {
335       return HttpDiskSyntax (  );
336     }
337 }