2 * Copyright (c) 2007, Hartmut Reuter,
3 * RZG, Max-Planck-Institut f. Plasmaphysik.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * Revised in 2010 by Chaz Chandler to enhance clientless operations.
29 * Now utilizes libafscp by Chaskiel Grundman.
30 * Work funded in part by Sine Nomine Associates (http://www.sinenomine.net/)
33 #include <afsconfig.h>
34 #include <afs/param.h>
42 #include <afs/smb_iocons.h>
44 #include <afs/cm_ioctl.h>
45 #include <afs/pioctl_nt.h>
46 #include <WINNT/syscfg.h>
48 #include <afs/afsint.h>
49 #define FSINT_COMMON_XG 1
55 #include <afs/vlserver.h>
56 #include <afs/ihandle.h>
57 #include <afs/com_err.h>
58 #include <afs/afscp.h>
63 #include <hcrypto/md5.h>
64 #ifdef AFS_PTHREAD_ENV
65 pthread_key_t uclient_key
;
68 static int lockFile(struct cmd_syndesc
*, void *);
69 static int readFile(struct cmd_syndesc
*, void *);
70 static int writeFile(struct cmd_syndesc
*, void *);
71 static void printDatarate(void);
72 static void summarizeDatarate(struct timeval
*, const char *);
73 static int CmdProlog(struct cmd_syndesc
*, char **, char **,
75 static int ScanFid(char *, struct AFSFid
*);
76 static afs_int32
GetVenusFidByFid(char *, char *, int, struct afscp_venusfid
**);
77 static afs_int32
GetVenusFidByPath(char *, char *, struct afscp_venusfid
**);
78 static int BreakUpPath(char *, char **, char **);
80 static char pnp
[AFSPATHMAX
]; /* filename of this program when called */
81 static int verbose
= 0; /* Set if -verbose option given */
82 static int clear
= 0; /* Set if -clear option given,
83 Unset if -crypt given; default is -crypt */
84 static int cellGiven
= 0; /* Set if -cell option given */
85 static int force
= 0; /* Set if -force option given */
86 static int readlock
= 0; /* Set if -readlock option given */
87 static int waittime
= 0; /* Set if -waittime option given */
88 static int useFid
= 0; /* Set if fidwrite/fidread/fidappend invoked */
89 static int append
= 0; /* Set if append/fidappend invoked */
90 static struct timeval starttime
, opentime
, readtime
, writetime
;
91 static afs_uint64 xfered
= 0;
92 static struct timeval now
;
94 static int Timezone
; /* Roken gettimeofday ignores the timezone */
96 static struct timezone Timezone
;
100 #define WRITEBUFLEN (BUFFLEN * 1024)
101 #define MEGABYTE_F 1048576.0f
104 static int md5sum
= 0; /* Set if -md5 option given */
108 afs_uint32 offset
; /* offset inside the buffer */
109 afs_uint32 buflen
; /* total length == BUFFLEN */
110 afs_uint32 used
; /* bytes used inside buffer */
115 * returns difference in seconds between two times
117 * \param[in] from start time
118 * \param[in] to end time
120 * \post returns "to" minus "from" in seconds
124 time_elapsed(struct timeval
*from
, struct timeval
*to
)
126 return (float)(to
->tv_sec
+ (to
->tv_usec
* 0.000001) - from
->tv_sec
-
127 (from
->tv_usec
* 0.000001));
131 * prints current average data transfer rate at no less than 30-second intervals
136 static float oldseconds
= 0.0;
137 static afs_uint64 oldxfered
= 0;
140 gettimeofday(&now
, &Timezone
);
141 seconds
= time_elapsed(&opentime
, &now
);
142 if ((seconds
- oldseconds
) > 30) {
143 fprintf(stderr
, "%llu MB transferred, present data rate = %.3f MB/sec.\n", xfered
>> 20, /* total bytes transferred, in MB */
144 (xfered
- oldxfered
) / (seconds
- oldseconds
) / MEGABYTE_F
);
146 oldseconds
= seconds
;
148 } /* printDatarate */
151 * prints overall average data transfer rate and elapsed time
153 * \param[in] tvp current time (to compare with file open time)
154 * \param[in] xfer_type string identify transfer type ("read" or "write")
157 summarizeDatarate(struct timeval
*tvp
, const char *xfer_type
)
159 float seconds
= time_elapsed(&opentime
, tvp
);
161 fprintf(stderr
, "Transfer of %llu bytes took %.3f sec.\n",
163 fprintf(stderr
, "Total data rate = %.03f MB/sec. for %s\n",
164 xfered
/ seconds
/ MEGABYTE_F
, xfer_type
);
165 } /* summarizeDatarate */
168 * prints final MD5 sum of all file data transferred
170 * \param[in] fname file name or FID
173 summarizeMD5(char *fname
)
175 afs_uint32 md5int
[4];
178 MD5_Final((char *) &md5int
[0], &md5
);
179 p
= fname
+ strlen(fname
);
186 fprintf(stderr
, "%08x%08x%08x%08x %s\n", htonl(md5int
[0]),
187 htonl(md5int
[1]), htonl(md5int
[2]), htonl(md5int
[3]), p
);
192 ConvertAFSPath(char **fnp
)
196 for (p
= *fnp
; *p
; p
++) {
202 if (p
[0] == '/' && p
[1] == '/')
205 #endif /* AFS_NT40_ENV */
208 * parses all command-line arguments
210 * \param[in] as arguments list
211 * \param[out] cellp cell name
212 * \param[out] realmp realm name
213 * \param[out] fnp filename (either fid or path)
214 * \param[out] slp "synthesized" (made up) data given
216 * \post returns 0 on success or -1 on error
220 CmdProlog(struct cmd_syndesc
*as
, char **cellp
, char **realmp
,
221 char **fnp
, char **slp
)
224 struct cmd_parmdesc
*pdp
;
227 afs_com_err(pnp
, EINVAL
, "(syndesc is null)");
231 /* determine which command was requested */
232 if (strncmp(as
->name
, "fid", 3) == 0) /* fidread/fidwrite/fidappend */
234 if ( (strcmp(as
->name
, "append") == 0) ||
235 (strcmp(as
->name
, "fidappend") == 0) )
236 append
= 1; /* global */
238 /* attempts to ensure loop is bounded: */
239 for (pdp
= as
->parms
, i
= 0; pdp
&& (i
< as
->nParms
); i
++, pdp
++) {
240 if (pdp
->items
!= NULL
) {
241 if (strcmp(pdp
->name
, "-verbose") == 0)
243 if (strcmp(pdp
->name
, "-clear") == 0)
245 if (strcmp(pdp
->name
, "-crypt") == 0)
247 else if (strcmp(pdp
->name
, "-md5") == 0)
248 md5sum
= 1; /* global */
249 else if (strcmp(pdp
->name
, "-cell") == 0) {
250 cellGiven
= 1; /* global */
251 *cellp
= pdp
->items
->data
;
252 } else if ( strcmp(pdp
->name
, "-file") == 0) {
253 *fnp
= pdp
->items
->data
;
256 #endif /* AFS_NT40_ENV */
257 } else if ( (strcmp(pdp
->name
, "-fid") == 0) ||
258 (strcmp(pdp
->name
, "-vnode") == 0) ) {
259 *fnp
= pdp
->items
->data
;
260 } else if (strcmp(pdp
->name
, "-force") == 0)
261 force
= 1; /* global */
262 else if (strcmp(pdp
->name
, "-synthesize") == 0)
263 *slp
= pdp
->items
->data
;
264 else if (strcmp(pdp
->name
, "-realm") == 0)
265 *realmp
= pdp
->items
->data
;
266 else if (strcmp(pdp
->name
, "-wait") == 0)
267 waittime
= atoi(pdp
->items
->data
);
268 else if (strcmp(pdp
->name
, "-readlock") == 0)
276 main(int argc
, char **argv
)
278 struct cmd_syndesc
*ts
;
282 /* try to get only the base name of this executable for use in logs */
284 char *p
= strdup(argv
[0]);
286 code
= BreakUpPath(p
, NULL
, &baseName
);
289 code
= BreakUpPath(argv
[0], NULL
, &baseName
);
292 strlcpy(pnp
, baseName
, AFSNAMEMAX
);
294 strlcpy(pnp
, argv
[0], AFSPATHMAX
);
297 #ifdef AFS_PTHREAD_ENV
298 opr_Verify(pthread_key_create(&uclient_key
, NULL
) == 0);
301 ts
= cmd_CreateSyntax("lock", lockFile
, (void *)LockWrite
, 0,
302 "lock a file in AFS");
303 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_REQUIRED
, "AFS-filename");
304 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
305 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
306 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
307 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
309 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
310 cmd_AddParm(ts
, "-waitseconds", CMD_SINGLE
, CMD_OPTIONAL
, "seconds to wait before giving up");
311 cmd_AddParm(ts
, "-readlock", CMD_FLAG
, CMD_OPTIONAL
, "read lock only");
313 ts
= cmd_CreateSyntax("fidlock", lockFile
, (void *)LockWrite
, 0,
314 "lock by FID a file from AFS");
315 cmd_AddParm(ts
, "-fid", CMD_SINGLE
, CMD_REQUIRED
,
316 "volume.vnode.uniquifier");
317 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
318 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
319 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
320 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
322 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
323 cmd_AddParm(ts
, "-waitseconds", CMD_SINGLE
, CMD_OPTIONAL
, "seconds to wait before giving up");
324 cmd_AddParm(ts
, "-readlock", CMD_FLAG
, CMD_OPTIONAL
, "read lock only");
326 ts
= cmd_CreateSyntax("unlock", lockFile
, (void *)LockRelease
, 0,
327 "unlock a file in AFS");
328 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_REQUIRED
, "AFS-filename");
329 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
330 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
331 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
332 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
334 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
335 cmd_AddParm(ts
, "-waitseconds", CMD_SINGLE
, CMD_OPTIONAL
, "seconds to wait before giving up");
337 ts
= cmd_CreateSyntax("fidunlock", lockFile
, (void *)LockRelease
, 0,
338 "unlock by FID a file from AFS");
339 cmd_AddParm(ts
, "-fid", CMD_SINGLE
, CMD_REQUIRED
,
340 "volume.vnode.uniquifier");
341 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
342 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
343 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
344 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
346 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
347 cmd_AddParm(ts
, "-waitseconds", CMD_SINGLE
, CMD_OPTIONAL
, "seconds to wait before giving up");
349 ts
= cmd_CreateSyntax("read", readFile
, NULL
, 0,
350 "read a file from AFS");
351 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_REQUIRED
, "AFS-filename");
352 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
353 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
354 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
355 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
356 cmd_AddParm(ts
, "-md5", CMD_FLAG
, CMD_OPTIONAL
, "calculate md5 checksum");
357 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
359 ts
= cmd_CreateSyntax("fidread", readFile
, CMD_REQUIRED
, 0,
360 "read on a non AFS-client a file from AFS");
361 cmd_AddParm(ts
, "-fid", CMD_SINGLE
, CMD_REQUIRED
,
362 "volume.vnode.uniquifier");
363 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
364 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
365 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
366 cmd_AddParm(ts
, "-md5", CMD_FLAG
, CMD_OPTIONAL
, "calculate md5 checksum");
367 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
369 ts
= cmd_CreateSyntax("write", writeFile
, NULL
, 0,
370 "write a file into AFS");
371 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_REQUIRED
, "AFS-filename");
372 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
373 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
374 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
375 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
376 cmd_AddParm(ts
, "-md5", CMD_FLAG
, CMD_OPTIONAL
, "calculate md5 checksum");
377 cmd_AddParm(ts
, "-force", CMD_FLAG
, CMD_OPTIONAL
,
378 "overwrite existing file");
379 cmd_AddParm(ts
, "-synthesize", CMD_SINGLE
, CMD_OPTIONAL
,
380 "create data pattern of specified length instead reading from stdin");
381 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
383 ts
= cmd_CreateSyntax("fidwrite", writeFile
, CMD_REQUIRED
, 0,
384 "write a file into AFS");
385 cmd_AddParm(ts
, "-vnode", CMD_SINGLE
, CMD_REQUIRED
,
386 "volume.vnode.uniquifier");
387 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
388 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
389 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
390 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
391 cmd_AddParm(ts
, "-md5", CMD_FLAG
, CMD_OPTIONAL
, "calculate md5 checksum");
392 cmd_AddParm(ts
, "-force", CMD_FLAG
, CMD_OPTIONAL
,
393 "overwrite existing file");
394 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
396 ts
= cmd_CreateSyntax("append", writeFile
, NULL
, 0,
397 "append to a file in AFS");
398 cmd_AddParm(ts
, "-file", CMD_SINGLE
, CMD_REQUIRED
, "AFS-filename");
399 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
400 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
401 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
402 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
403 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
405 ts
= cmd_CreateSyntax("fidappend", writeFile
, NULL
, 0,
406 "append to a file in AFS");
407 cmd_AddParm(ts
, "-vnode", CMD_SINGLE
, CMD_REQUIRED
,
408 "volume.vnode.uniquifier");
409 cmd_AddParm(ts
, "-cell", CMD_SINGLE
, CMD_OPTIONAL
, "cellname");
410 cmd_AddParm(ts
, "-verbose", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
411 cmd_AddParm(ts
, "-clear", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
412 cmd_AddParm(ts
, "-crypt", CMD_FLAG
, CMD_OPTIONAL
, (char *)0);
413 cmd_AddParm(ts
, "-realm", CMD_SINGLE
, CMD_OPTIONAL
, "REALMNAME");
415 if (afscp_Init(NULL
) != 0)
418 cmd_Dispatch(argc
, argv
);
425 * standardized way of parsing a File ID (FID) from command line input
427 * \param[in] fidString dot-delimited FID triple
428 * \param[out] fid pointer to the AFSFid to fill in
430 * \post The FID pointed to by "fid" is filled in which the parsed Volume,
431 * Vnode, and Uniquifier data. The string should be in the format
432 * of three numbers separated by dot (.) delimiters, representing
433 * (in order) the volume id, vnode number, and uniquifier.
434 * Example: "576821346.1.1"
437 ScanFid(char *fidString
, struct AFSFid
*fid
)
440 long unsigned int f1
, f2
, f3
;
443 i
= sscanf(fidString
, "%lu.%lu.%lu", &f1
, &f2
, &f3
);
444 fid
->Volume
= (afs_uint32
) f1
;
445 fid
->Vnode
= (afs_uint32
) f2
;
446 fid
->Unique
= (afs_uint32
) f3
;
453 afs_com_err(pnp
, code
, "(invalid FID triple: %s)", fidString
);
460 * look up cell info and verify FID info from user input
462 * \param[in] fidString string containing FID info
463 * \param[in] cellName cell name string
464 * \param[in] onlyRW bool: 1 = RW vol only, 0 = any vol type
465 * \param[out] avfpp pointer to venusfid info
467 * \post *avfpp will contain the VenusFid info found for the FID
468 * given by the used in the string fidString and zero is
469 * returned. If not found, an appropriate afs error code
470 * is returned and *avfpp will be NULL.
472 * \note Any non-NULL avfpp returned should later be freed with
473 * afscp_FreeFid() when no longer needed.
476 GetVenusFidByFid(char *fidString
, char *cellName
, int onlyRW
,
477 struct afscp_venusfid
**avfpp
)
481 struct afscp_volume
*avolp
;
483 if (*avfpp
== NULL
) {
484 *avfpp
= calloc(1, sizeof(struct afscp_venusfid
));
485 if ( *avfpp
== NULL
) {
491 if (cellName
== NULL
) {
492 (*avfpp
)->cell
= afscp_DefaultCell();
494 (*avfpp
)->cell
= afscp_CellByName(cellName
, NULL
);
496 if ((*avfpp
)->cell
== NULL
) {
497 if (afscp_errno
== 0)
504 code
= ScanFid(fidString
, &((*avfpp
)->fid
));
510 avolp
= afscp_VolumeById((*avfpp
)->cell
, (*avfpp
)->fid
.Volume
);
512 if (afscp_errno
== 0)
516 afs_com_err(pnp
, code
, "(finding volume %lu)",
517 afs_printable_uint32_lu((*avfpp
)->fid
.Volume
));
521 if ( onlyRW
&& (avolp
->voltype
!= RWVOL
) ) {
522 avolp
= afscp_VolumeByName((*avfpp
)->cell
, avolp
->name
, RWVOL
);
524 if (afscp_errno
== 0)
528 afs_com_err(pnp
, code
, "(finding volume %lu)",
529 afs_printable_uint32_lu((*avfpp
)->fid
.Volume
));
532 (*avfpp
)->fid
.Volume
= avolp
->id
; /* is this safe? */
535 code
= afscp_Stat((*avfpp
), &sbuf
);
537 afs_com_err(pnp
, code
, "(stat failed with code %d)", code
);
541 } /* GetVenusFidByFid */
544 * Split a full path up into dirName and baseName components
546 * \param[in] fullPath can be absolute, relative, or local
547 * \param[out] dirName pointer to output string or NULL
548 * \param[out] baseName pointer to output string or NULL
550 * \post A buffer of appropriate size will be allocated into the output
551 * parameter baseName and the rightmost full path component of the
552 * fullPath copied into it; likewise, the other components of the
553 * fullPath (minus the trailing path separator) will be placed into
554 * the dirName output, which is also allocated to be the appropriate
555 * size. If either dirName or baseName are NULL, only the non-NULL
556 * pointer will be allocated and filled in (but both can't be null
557 * or it would be pointless) -- so the caller can retrieve, say,
558 * only baseName if desired. The return code is the number of
559 * strings allocated and copied:
560 * 0 if neither dirName nor baseName could be filled in
561 * 1 if either dirName or baseName were filled in
562 * 2 if both dirName and baseName were filled in
565 BreakUpPath(char *fullPath
, char **dirName
, char **baseName
)
568 size_t dirNameLen
= 0;
569 int code
= 0, useDirName
= 1, useBaseName
= 1;
571 if (fullPath
== NULL
) {
575 /* Track what we need to output and initialize output variables to NULL. */
580 if (baseName
== NULL
)
584 if (!useBaseName
&& !useDirName
) {
585 /* would be pointless to continue -- must be error in call */
588 lastSlash
= strrchr(fullPath
, '/');
589 if (lastSlash
!= NULL
) {
590 /* then lastSlash points to the last path separator in fullPath */
592 dirNameLen
= strlen(fullPath
) - strlen(lastSlash
);
593 *dirName
= strdup(fullPath
);
594 if (*dirName
!= NULL
) {
596 /* Wastes some memory, but avoids needing libroken. */
597 *dirName
[dirNameLen
] = '\0';
602 *baseName
= strdup(lastSlash
);
603 if (*baseName
!= NULL
)
607 /* there are no path separators in fullPath -- it's just a baseName */
609 *baseName
= strdup(fullPath
);
610 if (*baseName
!= NULL
)
618 * Get the VenusFid info available for the file at AFS path 'fullPath'.
619 * Works without pioctls/afsd by using libafscp. Analogous to
620 * get_file_cell() in the previous iteration of afsio.
622 * \param[in] fullPath the file name
623 * \param[in] cellName the cell name to look up
624 * \param[out] avfpp pointer to Venus FID info to be filled in
626 * \post If the path resolves successfully (using afscp_ResolvePath),
627 * then vfpp will contain the Venus FID info (cell info plus
628 * AFSFid) of the last path segment in fullPath.
631 GetVenusFidByPath(char *fullPath
, char *cellName
,
632 struct afscp_venusfid
**avfpp
)
636 if (fullPath
== NULL
) {
640 if (cellName
!= NULL
) {
641 code
= (afs_int32
) afscp_SetDefaultCell(cellName
);
647 *avfpp
= afscp_ResolvePath(fullPath
);
648 if (*avfpp
== NULL
) {
649 if (afscp_errno
== 0)
656 } /* GetVenusFidByPath */
659 lockFile(struct cmd_syndesc
*as
, void *arock
)
665 struct AFSFetchStatus OutStatus
;
666 struct afscp_venusfid
*avfp
= NULL
;
669 int locktype
= (int)(intptr_t) arock
;
672 /* stdout on Windows defaults to _O_TEXT mode */
673 _setmode(1, _O_BINARY
);
676 gettimeofday(&starttime
, &Timezone
);
678 CmdProlog(as
, &cell
, &realm
, &fname
, NULL
);
679 afscp_AnonymousAuth(1);
683 if ((locktype
== LockWrite
) && readlock
)
687 afscp_SetDefaultRealm(realm
);
690 afscp_SetDefaultCell(cell
);
693 code
= GetVenusFidByFid(fname
, cell
, 0, &avfp
);
695 code
= GetVenusFidByPath(fname
, cell
, &avfp
);
697 afs_com_err(pnp
, code
, "(file not found: %s)", fname
);
703 code
= afscp_GetStatus(avfp
, &OutStatus
);
705 afs_inet_ntoa_r(avfp
->cell
->fsservers
[0]->addrs
[0], ipv4_addr
);
706 afs_com_err(pnp
, code
, "(failed to get status of file %s from"
707 "server %s, code = %d)", fname
, ipv4_addr
, code
);
712 if (locktype
!= LockRelease
) {
713 while (OutStatus
.lockCount
!= 0) {
714 code
= afscp_WaitForCallback(avfp
, waittime
);
715 if ((code
== -1) && (afscp_errno
== ETIMEDOUT
))
717 if ((code
= afscp_GetStatus(avfp
, &OutStatus
)) != 0)
721 if (OutStatus
.lockCount
== 0) {
727 code
= afscp_Lock(avfp
, locktype
);
728 if ((code
== -1) && (afscp_errno
== EWOULDBLOCK
))
737 afs_com_err(pnp
, code
, "(failed to change lock status: %d)", afscp_errno
);
743 readFile(struct cmd_syndesc
*as
, void *unused
)
749 struct AFSFetchStatus OutStatus
;
750 struct afscp_venusfid
*avfp
= NULL
;
753 afs_int64 length
= 0, Len
;
758 int bufflen
= BUFFLEN
;
761 /* stdout on Windows defaults to _O_TEXT mode */
762 _setmode(1, _O_BINARY
);
765 gettimeofday(&starttime
, &Timezone
);
767 CmdProlog(as
, &cell
, &realm
, &fname
, NULL
);
768 afscp_AnonymousAuth(1);
776 afscp_SetDefaultRealm(realm
);
779 afscp_SetDefaultCell(cell
);
782 code
= GetVenusFidByFid(fname
, cell
, 0, &avfp
);
784 code
= GetVenusFidByPath(fname
, cell
, &avfp
);
787 afs_com_err(pnp
, code
, "(file not found: %s)", fname
);
791 if (avfp
->fid
.Vnode
& 1) {
793 afs_com_err(pnp
, code
, "(%s is a directory, not a file)", fname
);
798 code
= afscp_GetStatus(avfp
, &OutStatus
);
800 afs_inet_ntoa_r(avfp
->cell
->fsservers
[0]->addrs
[0], ipv4_addr
);
801 afs_com_err(pnp
, code
, "(failed to get status of file %s from"
802 "server %s, code = %d)", fname
, ipv4_addr
, code
);
807 gettimeofday(&opentime
, &Timezone
);
809 fprintf(stderr
, "Startup to find the file took %.3f sec.\n",
810 time_elapsed(&starttime
, &opentime
));
811 Len
= OutStatus
.Length_hi
;
813 Len
+= OutStatus
.Length
;
815 buf
= calloc(bufflen
, sizeof(char));
818 afs_com_err(pnp
, code
, "(cannot allocate buffer)");
823 while (!code
&& NonZeroInt64(length
)) {
824 if (length
> bufflen
)
827 len
= (afs_int32
) length
;
828 bytes
= afscp_PRead(avfp
, buf
, len
, Pos
);
830 code
= -3; /* what error name should we use here? */
832 MD5_Update(&md5
, buf
, len
);
834 len
= write(1, buf
, len
); /* to stdout */
847 gettimeofday(&readtime
, &Timezone
);
851 summarizeDatarate(&readtime
, "read");
859 writeFile(struct cmd_syndesc
*as
, void *unused
)
863 char *sSynthLen
= NULL
;
866 afs_int32 byteswritten
;
867 struct AFSFetchStatus OutStatus
;
868 struct AFSStoreStatus InStatus
;
869 struct afscp_venusfid
*dirvfp
= NULL
, *newvfp
= NULL
;
871 afs_int64 length
, Len
, synthlength
= 0, offset
= 0;
875 struct wbuf
*bufchain
= 0;
876 struct wbuf
*previous
, *tbuf
;
877 char *dirName
= NULL
;
878 char *baseName
= NULL
;
882 /* stdin on Windows defaults to _O_TEXT mode */
883 _setmode(0, _O_BINARY
);
885 memset(&InStatus
, 0, sizeof(InStatus
));
887 CmdProlog(as
, &cell
, &realm
, &fname
, &sSynthLen
);
888 afscp_AnonymousAuth(1);
893 afscp_SetDefaultRealm(realm
);
896 afscp_SetDefaultCell(cell
);
899 code
= util_GetInt64(sSynthLen
, &synthlength
);
901 afs_com_err(pnp
, code
, "(invalid value for synthesize length %s)",
909 code
= GetVenusFidByFid(fname
, cell
, 1, &newvfp
);
911 afs_com_err(pnp
, code
, "(GetVenusFidByFid returned code %d)", code
);
915 code
= GetVenusFidByPath(fname
, cell
, &newvfp
);
916 if (code
== 0) { /* file was found */
921 * file cannot already exist if specified by path and not
922 * appending to it unless user forces overwrite
925 afs_com_err(pnp
, code
, "(use -force to overwrite)");
928 } else { /* file not found */
931 afs_com_err(pnp
, code
, "(cannot append to non-existent file)");
935 if (!append
&& !overWrite
) { /* must create a new file in this case */
936 if ( BreakUpPath(fname
, &dirName
, &baseName
) != 2 ) {
938 afs_com_err(pnp
, code
, "(must provide full AFS path)");
942 code
= GetVenusFidByPath(dirName
, cell
, &dirvfp
);
943 afscp_FreeFid(newvfp
); /* release now-unneeded fid */
946 afs_com_err(pnp
, code
, "(is dir %s in AFS?)", dirName
);
952 if ( (newvfp
!= NULL
) && (newvfp
->fid
.Vnode
& 1) ) {
954 afs_com_err(pnp
, code
, "(%s is a directory, not a file)", fname
);
957 gettimeofday(&starttime
, &Timezone
);
959 InStatus
.UnixModeBits
= 0644;
960 InStatus
.Mask
= AFS_SETMODE
+ AFS_FSYNC
;
961 if (newvfp
== NULL
) {
962 code
= afscp_CreateFile(dirvfp
, baseName
, &InStatus
, &newvfp
);
964 afs_com_err(pnp
, code
,
965 "(could not create file %s in directory %lu.%lu.%lu)",
966 baseName
, afs_printable_uint32_lu(dirvfp
->fid
.Volume
),
967 afs_printable_uint32_lu(dirvfp
->fid
.Vnode
),
968 afs_printable_uint32_lu(dirvfp
->fid
.Unique
));
972 code
= afscp_GetStatus(newvfp
, &OutStatus
);
974 afs_inet_ntoa_r(newvfp
->cell
->fsservers
[0]->addrs
[0], ipv4_addr
);
975 afs_com_err(pnp
, code
, "(failed to get status of file %s from"
976 "server %s, code = %d)", fname
, ipv4_addr
, code
);
980 if ( !append
&& !force
&&
981 (OutStatus
.Length
!= 0 || OutStatus
.Length_hi
!=0 ) ) {
983 * file exists, is of non-zero length, and we're not appending
984 * to it: user must force overwrite
985 * (covers fidwrite edge case)
988 afs_com_err(pnp
, code
, "(use -force to overwrite)");
993 Pos
= OutStatus
.Length_hi
;
994 Pos
= (Pos
<< 32) | OutStatus
.Length
;
997 previous
= (struct wbuf
*)&bufchain
;
1002 * currently, these two while loops (1) read the whole source file in
1003 * before (2) writing any of it out, meaning that afsio can't deal with
1004 * files larger than the maximum amount of memory designated for
1005 * reading a file in (WRITEBUFLEN).
1006 * Consider going to a single loop, like in readFile(), though will
1007 * have implications on timing statistics (such as the "Startup to
1008 * find the file" time, below).
1011 while (Len
< WRITEBUFLEN
) {
1012 tbuf
= calloc(1, sizeof(struct wbuf
));
1016 afs_com_err(pnp
, code
, "(cannot allocate buffer)");
1021 tbuf
->buflen
= BUFFLEN
;
1023 afs_int64 ll
, l
= tbuf
->buflen
;
1024 if (l
> synthlength
)
1026 for (ll
= 0; ll
< l
; ll
+= 4096) {
1027 sprintf(&tbuf
->buf
[ll
], "Offset (0x%x, 0x%x)\n",
1028 (unsigned int)((offset
+ ll
) >> 32),
1029 (unsigned int)((offset
+ ll
) & 0xffffffff));
1033 tbuf
->used
= (afs_int32
) l
;
1035 tbuf
->used
= read(0, &tbuf
->buf
, tbuf
->buflen
); /* from stdin */
1036 if (tbuf
->used
== 0) {
1041 MD5_Update(&md5
, &tbuf
->buf
, tbuf
->used
);
1042 previous
->next
= tbuf
;
1046 gettimeofday(&opentime
, &Timezone
);
1048 fprintf(stderr
, "Startup to find the file took %.3f sec.\n",
1049 time_elapsed(&starttime
, &opentime
));
1051 while (!code
&& bytes
) {
1055 for (tbuf
= bufchain
; tbuf
; tbuf
= tbuf
->next
) {
1056 if (tbuf
->used
== 0)
1058 byteswritten
= afscp_PWrite(newvfp
, tbuf
->buf
,
1059 tbuf
->used
, Pos
+ xfered
);
1060 if (byteswritten
!= tbuf
->used
) {
1061 fprintf(stderr
,"Only %d instead of %" AFS_INT64_FMT
" bytes transferred by rx_Write()\n", byteswritten
, length
);
1062 fprintf(stderr
, "At %" AFS_UINT64_FMT
" bytes from the end\n", length
);
1066 xfered
+= tbuf
->used
;
1069 length
-= tbuf
->used
;
1075 for (tbuf
= bufchain
; tbuf
; tbuf
= tbuf
->next
) {
1078 afs_int64 ll
, l
= tbuf
->buflen
;
1079 if (l
> synthlength
)
1081 for (ll
= 0; ll
< l
; ll
+= 4096) {
1082 sprintf(&tbuf
->buf
[ll
], "Offset (0x%x, 0x%x)\n",
1083 (unsigned int)((offset
+ ll
) >> 32),
1084 (unsigned int)((offset
+ ll
) & 0xffffffff));
1088 tbuf
->used
= (afs_int32
) l
;
1090 tbuf
->used
= read(0, &tbuf
->buf
, tbuf
->buflen
); /* from stdin */
1094 MD5_Update(&md5
, &tbuf
->buf
, tbuf
->used
);
1096 bytes
+= tbuf
->used
;
1101 gettimeofday(&writetime
, &Timezone
);
1103 afs_com_err(pnp
, code
, "(%s failed with code %d)", as
->name
,
1105 } else if (verbose
) {
1106 summarizeDatarate(&writetime
, "write");
1110 bufchain
= tbuf
->next
;
1115 summarizeMD5(fname
);
1120 afscp_FreeFid(newvfp
);
1121 afscp_FreeFid(dirvfp
);