1 /*
2  *  LABEL.C - label internal command.
3  *
4  *
5  *  History:
6  *
7  *    10-Dec-1998 (Eric Kohl)
8  *        Started.
9  *
10  *    11-Dec-1998 (Eric Kohl)
11  *        Finished.
12  *
13  *    19-Jan-1998 (Eric Kohl)
14  *        Unicode ready!
15  *
16  *    28-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
17  *        Remove all hardcoded strings in En.rc
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include <windef.h>
24 #include <winbase.h>
25 #include <wincon.h>
26 #include <winnls.h>
27 #include <winuser.h>
28 
29 #include <conutils.h>
30 
31 #include "resource.h"
32 
33 #define MAX_LABEL_LENGTH 32
34 #define MAX_DRIVE_LENGTH  2
35 
36 
37 static
38 VOID
39 ConFormatMessage(PCON_STREAM Stream, DWORD MessageId, ...)
40 {
41     va_list arg_ptr;
42 
43     va_start(arg_ptr, MessageId);
44     ConMsgPrintfV(Stream,
45                   FORMAT_MESSAGE_FROM_SYSTEM,
46                   NULL,
47                   MessageId,
48                   LANG_USER_DEFAULT,
49                   &arg_ptr);
50     va_end(arg_ptr);
51 }
52 
53 
54 static
55 VOID
56 ConInString(LPWSTR lpInput, DWORD dwLength)
57 {
58     DWORD dwOldMode;
59     DWORD dwRead = 0;
60     HANDLE hFile;
61     LPWSTR p;
62     PCHAR pBuf;
63 
64     pBuf = (PCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength - 1);
65 
66     hFile = GetStdHandle(STD_INPUT_HANDLE);
67     GetConsoleMode(hFile, &dwOldMode);
68 
69     SetConsoleMode(hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
70 
71     ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
72 
73     MultiByteToWideChar(GetConsoleCP(), 0, pBuf, dwRead, lpInput, dwLength - 1);
74     HeapFree(GetProcessHeap(), 0, pBuf);
75 
76     for (p = lpInput; *p; p++)
77     {
78         if (*p == L'\x0d')
79         {
80             *p = UNICODE_NULL;
81             break;
82         }
83     }
84 
85     SetConsoleMode(hFile, dwOldMode);
86 }
87 
88 
89 static
90 BOOL
91 IsValidPathName(LPCWSTR pszPath)
92 {
93     WCHAR szOldPath[MAX_PATH];
94     BOOL  bResult;
95 
96     GetCurrentDirectoryW(MAX_PATH, szOldPath);
97     bResult = SetCurrentDirectoryW(pszPath);
98 
99     SetCurrentDirectoryW(szOldPath);
100 
101     return bResult;
102 }
103 
104 
105 static
106 BOOL
107 PromptYesNo(VOID)
108 {
109     WCHAR szOptions[4];
110     WCHAR szInput[16];
111     BOOL bResult = FALSE;
112 
113     LoadString(GetModuleHandle(NULL), STRING_LABEL_OPTIONS, szOptions, ARRAYSIZE(szOptions));
114 
115     for (;;)
116     {
117         ConPuts(StdOut, L"\n");
118         ConResPuts(StdOut, STRING_LABEL_PROMPT);
119 
120         ConInString(szInput, ARRAYSIZE(szInput));
121 
122         if (towupper(szInput[0]) == szOptions[0])
123         {
124             bResult = TRUE;
125             break;
126         }
127         else if (towupper(szInput[0]) == szOptions[1])
128         {
129             bResult = FALSE;
130             break;
131         }
132 
133         ConPuts(StdOut, L"\n");
134     }
135 
136     ConPuts(StdOut, L"\n");
137 
138     return bResult;
139 }
140 
141 
142 int wmain(int argc, WCHAR *argv[])
143 {
144     WCHAR szRootPath[] = L" :\\";
145     WCHAR szBuffer[80] = L"";
146     WCHAR szLabel[80] = L"";
147     WCHAR szOldLabel[80];
148     DWORD dwSerialNr;
149     INT len, i;
150 
151     /* Initialize the Console Standard Streams */
152     ConInitStdStreams();
153 
154     /* print help */
155     if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
156     {
157         ConResPuts(StdOut, STRING_LABEL_HELP);
158         return 0;
159     }
160 
161     if (argc > 1)
162     {
163         len = 0;
164         for (i = 1; i < argc; i++)
165         {
166             if (i > 1)
167                 len++;
168             len += wcslen(argv[i]);
169         }
170 
171         if (len > MAX_LABEL_LENGTH + MAX_DRIVE_LENGTH)
172         {
173             ConResPuts(StdOut, STRING_ERROR_INVALID_LABEL);
174             return 1;
175         }
176 
177         for (i = 1; i < argc; i++)
178         {
179             if (i > 1)
180                 wcscat(szBuffer, L" ");
181             wcscat(szBuffer, argv[i]);
182         }
183     }
184 
185     if (wcslen(szBuffer) > 0)
186     {
187         if (szBuffer[1] == L':')
188         {
189             szRootPath[0] = towupper(szBuffer[0]);
190             wcscpy(szLabel, &szBuffer[2]);
191         }
192         else
193         {
194             wcscpy(szLabel, szBuffer);
195         }
196     }
197 
198     if (wcslen(szLabel) > MAX_LABEL_LENGTH)
199     {
200         ConResPuts(StdOut, STRING_ERROR_INVALID_LABEL);
201         return 1;
202     }
203 
204     if (szRootPath[0] == L' ')
205     {
206         /* get label of current drive */
207         WCHAR szCurPath[MAX_PATH];
208         GetCurrentDirectoryW(MAX_PATH, szCurPath);
209         szRootPath[0] = szCurPath[0];
210     }
211 
212     /* check root path */
213     if (!IsValidPathName(szRootPath))
214     {
215         ConResPuts(StdErr, STRING_ERROR_INVALID_DRIVE);
216         return 1;
217     }
218 
219     if (wcslen(szLabel) == 0)
220     {
221         GetVolumeInformationW(szRootPath, szOldLabel, ARRAYSIZE(szOldLabel), &dwSerialNr,
222                               NULL, NULL, NULL, 0);
223 
224         /* print drive info */
225         if (szOldLabel[0] != UNICODE_NULL)
226         {
227             ConResPrintf(StdOut, STRING_LABEL_TEXT1, towupper(szRootPath[0]), szOldLabel);
228         }
229         else
230         {
231             ConResPrintf(StdOut, STRING_LABEL_TEXT2, towupper(szRootPath[0]));
232         }
233 
234         /* print the volume serial number */
235         ConResPrintf(StdOut, STRING_LABEL_TEXT3, HIWORD(dwSerialNr), LOWORD(dwSerialNr));
236 
237         ConResPuts(StdOut, STRING_LABEL_TEXT4);
238 
239         ConInString(szLabel, ARRAYSIZE(szLabel));
240         ConPuts(StdOut, L"\n");
241 
242         if (wcslen(szLabel) == 0)
243         {
244             if (PromptYesNo() == FALSE)
245                 return 0;
246         }
247     }
248 
249     if (!SetVolumeLabelW(szRootPath, szLabel))
250     {
251         ConFormatMessage(StdOut, GetLastError());
252         return 1;
253     }
254 
255     return 0;
256 }
257 
258 /* EOF */
259