From 1dc2c0a175c85e0ce2e943a10dd1d95b65c553ce Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Mon, 25 May 2026 23:16:31 +0200 Subject: [PATCH] Quota-Backend-Cleanup/Logging --- src/connect.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++---- src/nwvolume.c | 44 +++++++++++++++++++++--------- 2 files changed, 100 insertions(+), 18 deletions(-) diff --git a/src/connect.c b/src/connect.c index bb4041b..4b1a6c1 100644 --- a/src/connect.c +++ b/src/connect.c @@ -1298,7 +1298,7 @@ static time_t nw_2_un_time_parts(uint16 xdate, uint16 xtime) #define DM_NCP22_25_SUPPORTED_BITS \ (DM_ATTRIBUTES | DM_CREATE_DATE | DM_CREATE_TIME | DM_CREATOR_ID | \ DM_NCP22_25_ARCHIVE_BITS | DM_NCP22_25_TIME_BITS | \ - DM_INHERITED_RIGHTS_MASK) + DM_MODIFIER_ID | DM_INHERITED_RIGHTS_MASK | DM_MAXIMUM_SPACE) static int set_ncp22_25_times(int volume, char *unixname, struct stat *stb, NW_SET_DIR_INFO *f, uint32 change_mask, @@ -1436,6 +1436,59 @@ static int set_ncp22_25_file_info(char *unixname, return(result); } + +static int set_ncp22_25_maximum_space(int volume, char *unixname, + struct stat *stb, + NW_SET_DIR_INFO *f, + uint32 change_mask, + int is_dir) +{ + uint32 max_space; + uint32 quota; + int result; + + if (!(change_mask & DM_MAXIMUM_SPACE)) + return(0); + + /* NetWare exposes maximum space on directory entries. mars_nwe already + * has a Linux user-quota backend for volume restrictions; use that as the + * closest available mapping. Files have no max_space field in the DOS + * layout, so ignore the bit if a client sends it for a file. + */ + if (!is_dir) { + XDPRINTF((5,0, + "NCP22/25 maximum space ignored for file %s", + unixname ? unixname : "")); + return(0); + } + + if (tru_eff_rights_exists(volume, unixname, stb, TRUSTEE_M)) + return(-0x8c); + + max_space = GET_BE32(f->u.d.max_space); + + /* Treat the common unlimited sentinels as "remove restriction". */ + if (max_space == MAX_U32 || max_space == 0x40000000UL) + quota = 0; + else + quota = max_space; + + result = nw_set_vol_restrictions((uint8)volume, act_uid, quota); + if (result) { + /* If quota support is not compiled/enabled, do not break old clients. */ + XDPRINTF((5,0, + "NCP22/25 maximum space quota ignored: vol=%d uid=%d max=0x%08lx rc=%d", + volume, act_uid, (unsigned long)max_space, result)); + if (result == -0xfb) + return(0); + } else { + XDPRINTF((5,0, + "NCP22/25 maximum space quota set: vol=%d uid=%d max=0x%08lx quota=0x%08lx", + volume, act_uid, (unsigned long)max_space, (unsigned long)quota)); + } + return(result); +} + static void log_ncp22_25_change_bits(uint32 change_mask) { uint32 unsupported = change_mask & ~DM_NCP22_25_SUPPORTED_BITS; @@ -1448,9 +1501,8 @@ static void log_ncp22_25_change_bits(uint32 change_mask) if (unsupported) { XDPRINTF((5,0, - "NCP22/25 unsupported change bits ignored: maxspace=%d other=0x%08lx", - !!(change_mask & DM_MAXIMUM_SPACE), - (unsigned long)(unsupported & ~DM_MAXIMUM_SPACE))); + "NCP22/25 unsupported change bits ignored: other=0x%08lx", + (unsigned long)unsupported)); } } @@ -3101,7 +3153,15 @@ void get_dos_dir_attrib(NW_DOS_DIR_INFO *f, } un_date_2_nw(stb->st_mtime, f->modify_date, 0); un_time_2_nw(stb->st_mtime, f->modify_time, 0); - U32_TO_BE32(MAX_U32, f->max_space); + { + uint32 quota = MAX_U32; + uint32 inuse = 0; + if (!nw_get_vol_restrictions((uint8)volume, act_uid, "a, &inuse)) { + U32_TO_BE32(quota, f->max_space); + } else { + U32_TO_BE32(MAX_U32, f->max_space); + } + } } @@ -3215,6 +3275,10 @@ int nw_set_a_directory_entry(int dirhandle, completition=set_ncp22_25_file_info(unixname, f, change_mask, S_ISDIR(stbuff.st_mode)); } + if (!completition) { + completition=set_ncp22_25_maximum_space(nwpath.volume, unixname, + &stbuff, f, change_mask, S_ISDIR(stbuff.st_mode)); + } if (S_ISDIR(stbuff.st_mode)) { if (change_mask & DM_INHERITED_RIGHTS_MASK) { int result=tru_set_inherited_mask(nwpath.volume, unixname, diff --git a/src/nwvolume.c b/src/nwvolume.c index 2b1c62c..deacb77 100644 --- a/src/nwvolume.c +++ b/src/nwvolume.c @@ -886,6 +886,7 @@ int get_volume_user_trustee(int volume, uint32 id, #include #include #include +#include /* Return the device special file that the specified path uses */ const char *find_device_file(const char *path) @@ -894,16 +895,18 @@ const char *find_device_file(const char *path) dev_t dev; struct mntent *mntent; FILE *fp; - const char *mount_device; + static char mount_device[512]; + mount_device[0] = '\0'; if (path == (char *) NULL || *path == '\0' || stat(path, &s) != 0) return((char *) NULL); dev = s.st_dev; if ((fp=setmntent(MOUNTED, "r")) == (FILE *) NULL) return((char *) NULL); - mount_device = (char *) NULL; while (!ferror(fp)) { - /* mntent will be a static struct mntent */ + /* mntent will be a static struct mntent. Copy the device name before + * endmntent(), do not return a pointer into libc's mount table buffer. + */ mntent = getmntent(fp); if (mntent == (struct mntent *) NULL) break; @@ -911,14 +914,14 @@ const char *find_device_file(const char *path) if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) { if (s.st_rdev == dev) { /* Found it */ - mount_device = mntent->mnt_fsname; + strmaxcpy(mount_device, mntent->mnt_fsname, sizeof(mount_device)-1); break; } } } } endmntent(fp); - return(mount_device); + return(mount_device[0] ? mount_device : (char *) NULL); } @@ -978,8 +981,11 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota) if (volnr >= used_nw_volumes || nw_volumes == (NW_VOL *) NULL) return(-0x98); device=find_device_file(nw_volumes[volnr].unixname); - if (device == (char *) NULL) + if (device == (char *) NULL) { + XDPRINTF((2,0, "nw_set_vol_restrictions: no device for volume=%d path=%s", + volnr, nw_volumes[volnr].unixname)); return(-0x98); + } /* If this call fails then it it probable that quotas are not enabled * on the specified device. Someone needs to set the error number @@ -987,8 +993,11 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota) */ res=su_quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk); - if (res != 0) - return(0); + if (res != 0) { + XDPRINTF((2,0, "Get quota before set failed device=%s uid=%d errno=%d", + device, uid, errno)); + return(0); /* Quotas are probably not enabled. Keep old compatibility. */ + } dqblk.dqb_bhardlimit = quota; dqblk.dqb_bsoftlimit = quota; if (quota == 0) @@ -1000,9 +1009,12 @@ int nw_set_vol_restrictions(uint8 volnr, int uid, uint32 quota) dqblk.dqb_ihardlimit, dqblk.dqb_curinodes)); - (void)su_quotactl(QCMD(Q_SETQLIM, USRQUOTA), device, uid, (caddr_t) &dqblk); - - + res=su_quotactl(QCMD(Q_SETQLIM, USRQUOTA), device, uid, (caddr_t) &dqblk); + if (res != 0) { + XDPRINTF((2,0, "Set quota failed device=%s uid=%d quota=%dK errno=%d", + device, uid, quota, errno)); + return(-0xfb); + } return(0); } @@ -1018,16 +1030,22 @@ int nw_get_vol_restrictions(uint8 volnr, int uid, uint32 *quota, uint32 *inuse) return(-0x98); device=find_device_file(nw_volumes[volnr].unixname); - if (device == (char *) NULL) + if (device == (char *) NULL) { + XDPRINTF((2,0, "nw_get_vol_restrictions: no device for volume=%d path=%s", + volnr, nw_volumes[volnr].unixname)); return(-0x98); + } XDPRINTF((2,0, "Get quota for uid %d on device %s", uid, device)); res=su_quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device, uid, (caddr_t) &dqblk); - if (res != 0) + if (res != 0) { + XDPRINTF((2,0, "Get quota failed device=%s uid=%d errno=%d", + device, uid, errno)); return(0); /* Quotas are probably not enabled */ + } if (dqblk.dqb_bhardlimit == 0) { *quota = 0x40000000; *inuse = 0;