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];
146     WCHAR szLabel[80];
147     WCHAR szOldLabel[80];
148     DWORD dwSerialNr;
149     INT len, i;
150 
151     /* Initialize the Console Standard Streams */
152     ConInitStdStreams();
153 
154     /* set empty label string */
155     szLabel[0] = UNICODE_NULL;
156 
157     /* print help */
158     if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
159     {
160         ConResPuts(StdOut, STRING_LABEL_HELP);
161         return 0;
162     }
163 
164     if (argc > 1)
165     {
166         len = 0;
167         for (i = 1; i < argc; i++)
168         {
169             if (i > 1)
170                 len++;
171             len += wcslen(argv[i]);
172         }
173 
174         if (len > MAX_LABEL_LENGTH + MAX_DRIVE_LENGTH)
175         {
176             ConResPuts(StdOut, STRING_ERROR_INVALID_LABEL);
177             return 1;
178         }
179 
180         for (i = 1; i < argc; i++)
181         {
182             if (i > 1)
183                 wcscat(szBuffer, L" ");
184             wcscat(szBuffer, argv[i]);
185         }
186     }
187 
188     if (wcslen(szBuffer) > 0)
189     {
190         if (szBuffer[1] == L':')
191         {
192             szRootPath[0] = towupper(szBuffer[0]);
193             wcscpy(szLabel, &szBuffer[2]);
194         }
195         else
196         {
197             wcscpy(szLabel, szBuffer);
198         }
199     }
200 
201     if (wcslen(szLabel) > MAX_LABEL_LENGTH)
202     {
203         ConResPuts(StdOut, STRING_ERROR_INVALID_LABEL);
204         return 1;
205     }
206 
207     if (szRootPath[0] == L' ')
208     {
209         /* get label of current drive */
210         WCHAR szCurPath[MAX_PATH];
211         GetCurrentDirectoryW(MAX_PATH, szCurPath);
212         szRootPath[0] = szCurPath[0];
213     }
214 
215     /* check root path */
216     if (!IsValidPathName(szRootPath))
217     {
218         ConResPuts(StdErr, STRING_ERROR_INVALID_DRIVE);
219         return 1;
220     }
221 
222     if (wcslen(szLabel) == 0)
223     {
224         GetVolumeInformationW(szRootPath, szOldLabel, ARRAYSIZE(szOldLabel), &dwSerialNr,
225                               NULL, NULL, NULL, 0);
226 
227         /* print drive info */
228         if (szOldLabel[0] != UNICODE_NULL)
229         {
230             ConResPrintf(StdOut, STRING_LABEL_TEXT1, towupper(szRootPath[0]), szOldLabel);
231         }
232         else
233         {
234             ConResPrintf(StdOut, STRING_LABEL_TEXT2, towupper(szRootPath[0]));
235         }
236 
237         /* print the volume serial number */
238         ConResPrintf(StdOut, STRING_LABEL_TEXT3, HIWORD(dwSerialNr), LOWORD(dwSerialNr));
239 
240         ConResPuts(StdOut, STRING_LABEL_TEXT4);
241 
242         ConInString(szLabel, ARRAYSIZE(szLabel));
243         ConPuts(StdOut, L"\n");
244 
245         if (wcslen(szLabel) == 0)
246         {
247             if (PromptYesNo() == FALSE)
248                 return 0;
249         }
250     }
251 
252     if (!SetVolumeLabelW(szRootPath, szLabel))
253     {
254         ConFormatMessage(StdOut, GetLastError());
255         return 1;
256     }
257 
258     return 0;
259 }
260 
261 /* EOF */
262