fs: fix setserverprefs where long is larger than afs_int32
[openafs.git] / src / venus / fs.c
index 06b3b6d..31d20d4 100644 (file)
@@ -305,17 +305,33 @@ Parent(char *apath)
     return tspace;
 }
 
-enum rtype { add, destroy, deny };
+                                /* added relative add resp. delete    */
+                                /* (so old add really means to set)   */
+enum rtype { add, destroy, deny, reladd, reldel };
 
 static afs_int32
 Convert(char *arights, int dfs, enum rtype *rtypep)
 {
-    int i, len;
     afs_int32 mode;
     char tc;
+    char *tcp;                  /* to walk through the rights string  */
 
     *rtypep = add;             /* add rights, by default */
 
+                                /* analyze last character of string   */
+    tcp = arights + strlen(arights);
+    if ( tcp-- > arights ) {    /* assure non-empty string            */
+        if ( *tcp == '+' )
+            *rtypep = reladd;   /* '+' indicates more rights          */
+        else if ( *tcp == '-' )
+            *rtypep = reldel;   /* '-' indicates less rights          */
+        else if ( *tcp == '=' )
+            *rtypep = add;      /* '=' also allows old behaviour      */
+        else
+            tcp++;              /* back to original null byte         */
+        *tcp = '\0';            /* do not disturb old strcmp-s        */
+    }
+
     if (dfs) {
        if (!strcmp(arights, "null")) {
            *rtypep = deny;
@@ -345,10 +361,9 @@ Convert(char *arights, int dfs, enum rtype *rtypep)
        *rtypep = destroy;      /* Remove entire entry */
        return 0;
     }
-    len = strlen(arights);
     mode = 0;
-    for (i = 0; i < len; i++) {
-       tc = *arights++;
+    tcp = arights;
+    while ((tc = *tcp++ )) {
        if (dfs) {
            if (tc == '-')
                continue;
@@ -455,20 +470,35 @@ SetDotDefault(struct cmd_item **aitemp)
 }
 
 static void
-ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights)
+ChangeList(struct Acl *al, afs_int32 plus, char *aname, afs_int32 arights,
+          enum rtype *artypep)
 {
     struct AclEntry *tlist;
     tlist = (plus ? al->pluslist : al->minuslist);
     tlist = FindList(tlist, aname);
     if (tlist) {
-       /* Found the item already in the list. */
-       tlist->rights = arights;
+       /* Found the item already in the list.
+        * modify rights in case of reladd and reladd only,
+        * use standard - add, ie. set - otherwise
+        */
+        if ( artypep == NULL )
+            tlist->rights = arights;
+        else if ( *artypep == reladd )
+            tlist->rights |= arights;
+        else if ( *artypep == reldel )
+            tlist->rights &= ~arights;
+        else
+            tlist->rights = arights;
+
        if (plus)
            al->nplus -= PruneList(&al->pluslist, al->dfs);
        else
            al->nminus -= PruneList(&al->minuslist, al->dfs);
        return;
     }
+    if ( artypep != NULL && *artypep == reldel )
+        return;                 /* can't reduce non-existing rights   */
+
     /* Otherwise we make a new item and plug in the new data. */
     tlist = (struct AclEntry *)malloc(sizeof(struct AclEntry));
     assert(tlist);
@@ -821,7 +851,7 @@ SetACLCmd(struct cmd_syndesc *as, void *arock)
                plusp = 0;
            if (rtype == destroy && ta->dfs)
                rights = -1;
-           ChangeList(ta, plusp, ui->data, rights);
+           ChangeList(ta, plusp, ui->data, rights, &rtype);
        }
        blob.in = AclToString(ta);
        blob.out_size = 0;
@@ -948,10 +978,11 @@ CopyACLCmd(struct cmd_syndesc *as, void *arock)
            }
            strcpy(ta->cell, fa->cell);
        }
+                                /* NULL rtype for standard handling   */
        for (tp = fa->pluslist; tp; tp = tp->next)
-           ChangeList(ta, 1, tp->name, tp->rights);
+           ChangeList(ta, 1, tp->name, tp->rights, NULL);
        for (tp = fa->minuslist; tp; tp = tp->next)
-           ChangeList(ta, 0, tp->name, tp->rights);
+           ChangeList(ta, 0, tp->name, tp->rights, NULL);
        blob.in = AclToString(ta);
        blob.out_size = 0;
        blob.in_size = 1 + strlen(blob.in);
@@ -3119,7 +3150,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
     afs_int32 code;
     struct cmd_item *ti;
     char name[80];
-    afs_int32 rank;
+    int rank;
     struct setspref *ssp;
     int error = 0;             /* -1 means error message printed,
                                 * >0 means errno value for unprinted message */
@@ -3146,7 +3177,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
            perror(ti->data);
            error = -1;
        } else {
-           while (fscanf(infd, "%79s%ld", name, (long int *)&rank) != EOF) {
+           while (fscanf(infd, "%79s%d", name, &rank) != EOF) {
                code = addServer(name, (unsigned short)rank);
                if (code)
                    error = code;
@@ -3156,7 +3187,7 @@ SetPrefCmd(struct cmd_syndesc *as, void *arock)
 
     ti = as->parms[3].items;   /* -stdin */
     if (ti) {
-       while (scanf("%79s%ld", name, (long int *)&rank) != EOF) {
+       while (scanf("%79s%d", name, &rank) != EOF) {
            code = addServer(name, (unsigned short)rank);
            if (code)
                error = code;