2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
15 #include <afs/com_err.h>
16 #include <afs/afs_consts.h>
31 #include <WINNT\afsreg.h>
39 #define MAXINSIZE 1300 /* pioctl complains if data is larger than this */
41 static char space[AFS_PIOCTL_MAXSIZE];
43 static char pn[] = "symlink";
44 static int rxInitDone = 0;
47 ListLinkCmd(struct cmd_syndesc *as, void *arock)
50 struct ViceIoctl blob;
53 char orig_name[1024]; /* Original name */
54 char true_name[1024]; /*``True'' dirname (e.g., symlink target)*/
55 char parent_dir[1024]; /*Parent directory of true name*/
56 char *last_component; /*Last component of true name*/
57 cm_ioctlQueryOptions_t options;
60 for(ti=as->parms[0].items; ti; ti=ti->next) {
65 if( FAILED(StringCbCopy(orig_name, sizeof(orig_name), ti->data))) {
66 fprintf (stderr, "ListLinkCmd - input path too long");
71 if( FAILED(StringCbCopy(true_name, sizeof(true_name), ti->data))) {
72 fprintf (stderr, "ListLinkCmd - input path too long");
78 * Find rightmost slash, if any.
80 last_component = (char *) strrchr(true_name, '\\');
82 last_component = (char *) strrchr(true_name, '/');
85 * Found it. Designate everything before it as the parent directory,
86 * everything after it as the final component. (explicitly relying
87 * on behavior of strncpy in this case.)
89 strncpy(parent_dir, true_name, last_component - true_name + 1);
90 parent_dir[last_component - true_name + 1] = 0;
91 last_component++; /*Skip the slash*/
94 * The following hack converts \\afs\foobar to \\afs\all\foobar.
95 * However, this hack should no longer be required as the pioctl()
96 * interface handles this conversion for us.
98 if (!fs_InAFS(parent_dir)) {
99 const char * nbname = fs_NetbiosName();
100 size_t len = strlen(nbname);
102 if (parent_dir[0] == '\\' && parent_dir[1] == '\\' &&
103 parent_dir[len+2] == '\\' &&
104 parent_dir[len+3] == '\0' &&
105 !strnicmp(nbname,&parent_dir[2],len))
107 if( FAILED(StringCbPrintf(parent_dir, sizeof(parent_dir), "\\\\%s\\all\\", nbname))) {
108 fprintf(stderr, "parent_dir cannot be populated");
113 fprintf(stderr,"'%s' is not in AFS.\n", parent_dir);
122 * No slash appears in the given file name. Set parent_dir to the current
123 * directory, and the last component as the given name.
125 fs_ExtractDriveLetter(true_name, parent_dir);
126 if( FAILED(StringCbCat(parent_dir, sizeof(parent_dir), "."))) {
127 fprintf (stderr, "parent_dir - not enough space");
130 last_component = true_name;
131 fs_StripDriveLetter(true_name, true_name, sizeof(true_name));
134 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
135 fprintf(stderr,"%s: you may not use '.' or '..' as the last component\n", pn);
136 fprintf(stderr,"%s: of a name in the 'symlink list' command.\n", pn);
141 /* Check the object type */
142 memset(&fid, 0, sizeof(fid));
143 memset(&options, 0, sizeof(options));
145 options.size = sizeof(options);
146 options.field_flags |= CM_IOCTL_QOPTS_FIELD_LITERAL;
148 blob.in_size = options.size; /* no variable length data */
151 blob.out_size = sizeof(cm_fid_t);
152 blob.out = (char *) &fid;
153 if (0 == pioctl_utf8(orig_name, VIOCGETFID, &blob, 1) &&
154 blob.out_size == sizeof(cm_fid_t)) {
155 options.field_flags |= CM_IOCTL_QOPTS_FIELD_FID;
158 fs_Die(errno, ti->data);
163 blob.out_size = sizeof(filetype);
164 blob.out = &filetype;
166 code = pioctl_utf8(orig_name, VIOC_GETFILETYPE, &blob, 1);
167 if (code || blob.out_size != sizeof(filetype)) {
168 fs_Die(errno, ti->data);
173 if (filetype != 3 /* symlink */) {
174 fprintf(stderr,"'%s' is a %s not a Symlink.\n",
175 orig_name, fs_filetypestr(filetype));
180 blob.in = last_component;
181 blob.in_size = (long)strlen(last_component)+1;
183 /* Now determine the symlink target */
184 blob.out_size = AFS_PIOCTL_MAXSIZE;
186 memset(space, 0, AFS_PIOCTL_MAXSIZE);
188 code = pioctl_utf8(parent_dir, VIOC_LISTSYMLINK, &blob, 1);
190 printf("'%s' is a symlink to '%.*s'\n",
197 fprintf(stderr,"'%s' is not a symlink.\n",
200 fs_Die(errno, (ti->data ? ti->data : parent_dir));
208 MakeLinkCmd(struct cmd_syndesc *as, void *arock)
211 struct ViceIoctl blob;
213 char link[1024] = "";
214 char target_buf[1024] = "";
215 char *target = target_buf;
219 if( FAILED(StringCbCopy(link, sizeof(link), as->parms[0].items->data))) {
220 fprintf (stderr, "MakeLinkCmd - link path too long");
223 if( FAILED(StringCbCopy(target, sizeof(target_buf), as->parms[1].items->data))) {
224 fprintf (stderr, "MakeLinkCmd - target path too long");
227 parent = fs_GetParent(link);
229 nbname = fs_NetbiosName();
230 nblen = (int)strlen(nbname);
232 if (!fs_InAFS(parent)) {
233 if (parent[0] == '\\' && parent[1] == '\\' &&
234 (parent[nblen+2] == '\\' && parent[nblen+3] == '\0' || parent[nblen+2] == '\0') &&
235 !strnicmp(nbname,&parent[2],nblen))
237 if( FAILED(StringCbPrintf(link, sizeof(link),
238 "%s%sall%s", parent, parent[nblen+2]?"":"\\",
239 &as->parms[0].items->data[strlen(parent)]))) {
240 fprintf(stderr, "link cannot be populated\n");
243 parent = fs_GetParent(link);
245 fprintf(stderr,"%s: symlinks must be created within the AFS file system\n", pn);
250 if ( fs_IsFreelanceRoot(parent) && !fs_IsAdmin() ) {
251 fprintf(stderr,"%s: Only AFS Client Administrators may alter the root.afs volume\n", pn);
256 * Fix up the target path to conform to unix notation
257 * if it is a UNC path to the AFS server name.
259 if (target[0] == '\\' && target[1] == '\\' &&
260 target[nblen+2] == '\\' &&
261 !strnicmp(nbname,&target[2],nblen))
264 for ( p=target; *p; p++) {
270 fprintf(stderr, "Creating symlink [%s] to [%s]\n", link, target);
272 /* create symlink with a special pioctl for Windows NT, since it doesn't
273 * have a symlink system call.
276 blob.in_size = 1 + (long)strlen(target);
279 code = pioctl_utf8(link, VIOC_SYMLINK, &blob, 0);
281 fs_Die(errno, as->parms[0].items->data);
288 * Delete AFS symlinks. Variables are used as follows:
289 * tbuffer: Set to point to the null-terminated directory name of the
290 * symlink (or ``.'' if none is provided)
291 * tp: Set to point to the actual name of the symlink to nuke.
294 RemoveLinkCmd(struct cmd_syndesc *as, void *arock)
297 struct ViceIoctl blob;
303 for(ti=as->parms[0].items; ti; ti=ti->next) {
305 tp = (char *) strrchr(ti->data, '\\');
307 tp = (char *) strrchr(ti->data, '/');
309 strncpy(tbuffer, ti->data, code=(afs_int32)(tp-ti->data+1)); /* the dir name */
311 tp++; /* skip the slash */
313 if (!fs_InAFS(tbuffer)) {
314 const char * nbname = fs_NetbiosName();
315 int len = (int)strlen(nbname);
317 if (tbuffer[0] == '\\' && tbuffer[1] == '\\' &&
318 tbuffer[len+2] == '\\' &&
319 tbuffer[len+3] == '\0' &&
320 !strnicmp(nbname,&tbuffer[2],len))
322 if( FAILED(StringCbPrintf(tbuffer, sizeof(tbuffer),
323 "\\\\%s\\all\\", nbname))) {
324 fprintf( stderr, "tbuffer cannot be populated\n");
328 fprintf(stderr,"'%s' is not in AFS.\n", tbuffer);
336 fs_ExtractDriveLetter(ti->data, tbuffer);
337 if( FAILED(StringCbCat(tbuffer, sizeof(tbuffer), "."))) {
338 fprintf (stderr, "tbuffer - not enough space");
342 fs_StripDriveLetter(tp, tp, strlen(tp) + 1);
345 blob.in_size = (int)strlen(tp)+1;
347 blob.out_size = sizeof(lsbuffer);
348 code = pioctl_utf8(tbuffer, VIOC_LISTSYMLINK, &blob, 0);
351 fprintf(stderr,"symlink: '%s' is not a symlink.\n", ti->data);
353 fs_Die(errno, ti->data);
355 continue; /* don't bother trying */
358 if ( fs_IsFreelanceRoot(tbuffer) && !fs_IsAdmin() ) {
359 fprintf(stderr,"symlink: Only AFS Client Administrators may alter the root.afs volume\n");
366 blob.in_size = (long)strlen(tp)+1;
367 code = pioctl_utf8(tbuffer, VIOC_DELSYMLINK, &blob, 0);
369 fs_Die(errno, ti->data);
375 static struct ViceIoctl gblob;
376 static int debug = 0;
379 wmain(int argc, wchar_t **wargv)
382 struct cmd_syndesc *ts;
386 WSAStartup(0x0101, &WSAjunk);
388 fs_SetProcessName(pn);
390 /* try to find volume location information */
392 argv = fs_MakeUtf8Cmdline(argc, wargv);
396 ts = cmd_CreateSyntax("list", ListLinkCmd, NULL, 0, "list symlink");
397 cmd_AddParm(ts, "-name", CMD_LIST, 0, "name");
399 ts = cmd_CreateSyntax("make", MakeLinkCmd, NULL, 0, "make symlink");
400 cmd_AddParm(ts, "-name", CMD_SINGLE, 0, "name");
401 cmd_AddParm(ts, "-to", CMD_SINGLE, 0, "target");
403 ts = cmd_CreateSyntax("remove", RemoveLinkCmd, NULL, 0, "remove symlink");
404 cmd_AddParm(ts, "-name", CMD_LIST, 0, "name");
405 cmd_CreateAlias(ts, "rm");
407 code = cmd_Dispatch(argc, argv);
409 fs_FreeUtf8CmdLine(argc, argv);